Merge pull request #74086 from vladimirvivien/csi-inline-volume-api

CSI Inline Volume Implementation
pull/564/head
Kubernetes Prow Robot 2019-03-08 13:02:55 -08:00 committed by GitHub
commit 83ff0f6c64
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 5230 additions and 2394 deletions

View File

@ -6087,6 +6087,38 @@
],
"type": "object"
},
"io.k8s.api.core.v1.CSIVolumeSource": {
"description": "Represents a source location of a volume to mount, managed by an external CSI driver",
"properties": {
"driver": {
"description": "Driver is the name of the CSI driver that handles this volume. Consult with your admin for the correct name as registered in the cluster.",
"type": "string"
},
"fsType": {
"description": "Filesystem type to mount. Ex. \"ext4\", \"xfs\", \"ntfs\". If not provided, the empty value is passed to the associated CSI driver which will determine the default filesystem to apply.",
"type": "string"
},
"nodePublishSecretRef": {
"$ref": "#/definitions/io.k8s.api.core.v1.LocalObjectReference",
"description": "NodePublishSecretRef is a reference to the secret object containing sensitive information to pass to the CSI driver to complete the CSI NodePublishVolume and NodeUnpublishVolume calls. This field is optional, and may be empty if no secret is required. If the secret object contains more than one secret, all secret references are passed."
},
"readOnly": {
"description": "Specifies a read-only configuration for the volume. Defaults to false (read/write).",
"type": "boolean"
},
"volumeAttributes": {
"additionalProperties": {
"type": "string"
},
"description": "VolumeAttributes stores driver-specific properties that are passed to the CSI driver. Consult your driver's documentation for supported values.",
"type": "object"
}
},
"required": [
"driver"
],
"type": "object"
},
"io.k8s.api.core.v1.Capabilities": {
"description": "Adds and removes POSIX capabilities from running containers.",
"properties": {
@ -8793,7 +8825,7 @@
},
"csi": {
"$ref": "#/definitions/io.k8s.api.core.v1.CSIPersistentVolumeSource",
"description": "CSI represents storage that handled by an external CSI driver (Beta feature)."
"description": "CSI represents storage that is handled by an external CSI driver (Beta feature)."
},
"fc": {
"$ref": "#/definitions/io.k8s.api.core.v1.FCVolumeSource",
@ -10940,6 +10972,10 @@
"$ref": "#/definitions/io.k8s.api.core.v1.ConfigMapVolumeSource",
"description": "ConfigMap represents a configMap that should populate this volume"
},
"csi": {
"$ref": "#/definitions/io.k8s.api.core.v1.CSIVolumeSource",
"description": "CSI (Container Storage Interface) represents storage that is handled by an external CSI driver (Alpha feature)."
},
"downwardAPI": {
"$ref": "#/definitions/io.k8s.api.core.v1.DownwardAPIVolumeSource",
"description": "DownwardAPI represents downward API about the pod that should populate this volume"
@ -11305,6 +11341,19 @@
],
"type": "object"
},
"io.k8s.api.extensions.v1beta1.AllowedCSIDriver": {
"description": "AllowedCSIDriver represents a single inline CSI Driver that is allowed to be used.",
"properties": {
"name": {
"description": "Name is the registered name of the CSI driver",
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
},
"io.k8s.api.extensions.v1beta1.AllowedFlexVolume": {
"description": "AllowedFlexVolume represents a single Flexvolume that is allowed to be used. Deprecated: use AllowedFlexVolume from policy API Group instead.",
"properties": {
@ -12302,6 +12351,13 @@
"description": "allowPrivilegeEscalation determines if a pod can request to allow privilege escalation. If unspecified, defaults to true.",
"type": "boolean"
},
"allowedCSIDrivers": {
"description": "AllowedCSIDrivers is a whitelist of inline CSI drivers that must be explicitly set to be embedded within a pod spec. An empty value means no CSI drivers can run inline within a pod spec.",
"items": {
"$ref": "#/definitions/io.k8s.api.extensions.v1beta1.AllowedCSIDriver"
},
"type": "array"
},
"allowedCapabilities": {
"description": "allowedCapabilities is a list of capabilities that can be requested to add to the container. Capabilities in this field may be added at the pod author's discretion. You must not list a capability in both allowedCapabilities and requiredDropCapabilities.",
"items": {
@ -13288,6 +13344,19 @@
}
]
},
"io.k8s.api.policy.v1beta1.AllowedCSIDriver": {
"description": "AllowedCSIDriver represents a single inline CSI Driver that is allowed to be used.",
"properties": {
"name": {
"description": "Name is the registered name of the CSI driver",
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
},
"io.k8s.api.policy.v1beta1.AllowedFlexVolume": {
"description": "AllowedFlexVolume represents a single Flexvolume that is allowed to be used.",
"properties": {
@ -13599,6 +13668,13 @@
"description": "allowPrivilegeEscalation determines if a pod can request to allow privilege escalation. If unspecified, defaults to true.",
"type": "boolean"
},
"allowedCSIDrivers": {
"description": "AllowedCSIDrivers is a whitelist of inline CSI drivers that must be explicitly set to be embedded within a pod spec. An empty value means no CSI drivers can run inline within a pod spec.",
"items": {
"$ref": "#/definitions/io.k8s.api.policy.v1beta1.AllowedCSIDriver"
},
"type": "array"
},
"allowedCapabilities": {
"description": "allowedCapabilities is a list of capabilities that can be requested to add to the container. Capabilities in this field may be added at the pod author's discretion. You must not list a capability in both allowedCapabilities and requiredDropCapabilities.",
"items": {

View File

@ -165,6 +165,10 @@ func ProbeControllerVolumePlugins(cloud cloudprovider.Interface, config kubectrl
allPlugins = append(allPlugins, azure_dd.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, photon_pd.ProbeVolumePlugins()...)
if utilfeature.DefaultFeatureGate.Enabled(features.CSIInlineVolume) {
allPlugins = append(allPlugins, csi.ProbeVolumePlugins()...)
}
return allPlugins
}

View File

@ -97,6 +97,10 @@ func VisitPodSecretNames(pod *api.Pod, visitor Visitor) bool {
if source.StorageOS.SecretRef != nil && !visitor(source.StorageOS.SecretRef.Name) {
return false
}
case source.CSI != nil:
if source.CSI.NodePublishSecretRef != nil && !visitor(source.CSI.NodePublishSecretRef.Name) {
return false
}
}
}
return true
@ -370,6 +374,9 @@ func dropDisabledFields(
}
dropDisabledProcMountField(podSpec, oldPodSpec)
dropDisabledCSIVolumeSourceAlphaFields(podSpec, oldPodSpec)
}
// dropDisabledRunAsGroupField removes disabled fields from PodSpec related
@ -423,6 +430,16 @@ func dropDisabledVolumeDevicesFields(podSpec, oldPodSpec *api.PodSpec) {
}
}
// dropDisabledCSIVolumeSourceAlphaFields removes disabled alpha fields from []CSIVolumeSource.
// This should be called from PrepareForCreate/PrepareForUpdate for all pod specs resources containing a CSIVolumeSource
func dropDisabledCSIVolumeSourceAlphaFields(podSpec, oldPodSpec *api.PodSpec) {
if !utilfeature.DefaultFeatureGate.Enabled(features.CSIInlineVolume) && !csiInUse(oldPodSpec) {
for i := range podSpec.Volumes {
podSpec.Volumes[i].CSI = nil
}
}
}
// subpathInUse returns true if the pod spec is non-nil and has a volume mount that makes use of the subPath feature
func subpathInUse(podSpec *api.PodSpec) bool {
if podSpec == nil {
@ -616,3 +633,16 @@ func subpathExprInUse(podSpec *api.PodSpec) bool {
}
return false
}
// csiInUse returns true if any pod's spec include inline CSI volumes.
func csiInUse(podSpec *api.PodSpec) bool {
if podSpec == nil {
return false
}
for i := range podSpec.Volumes {
if podSpec.Volumes[i].CSI != nil {
return true
}
}
return false
}

View File

@ -104,7 +104,11 @@ func TestPodSecrets(t *testing.T) {
VolumeSource: api.VolumeSource{
StorageOS: &api.StorageOSVolumeSource{
SecretRef: &api.LocalObjectReference{
Name: "Spec.Volumes[*].VolumeSource.StorageOS.SecretRef"}}}}},
Name: "Spec.Volumes[*].VolumeSource.StorageOS.SecretRef"}}}}, {
VolumeSource: api.VolumeSource{
CSI: &api.CSIVolumeSource{
NodePublishSecretRef: &api.LocalObjectReference{
Name: "Spec.Volumes[*].VolumeSource.CSI.NodePublishSecretRef"}}}}},
},
}
extractedNames := sets.NewString()
@ -136,6 +140,7 @@ func TestPodSecrets(t *testing.T) {
"Spec.Volumes[*].VolumeSource.ScaleIO.SecretRef",
"Spec.Volumes[*].VolumeSource.ISCSI.SecretRef",
"Spec.Volumes[*].VolumeSource.StorageOS.SecretRef",
"Spec.Volumes[*].VolumeSource.CSI.NodePublishSecretRef",
)
secretPaths := collectResourcePaths(t, "secret", nil, "", reflect.TypeOf(&api.Pod{}))
secretPaths = secretPaths.Difference(excludedSecretPaths)

View File

@ -35,6 +35,9 @@ func DropDisabledFields(pspSpec, oldPSPSpec *policy.PodSecurityPolicySpec) {
pspSpec.AllowedUnsafeSysctls = nil
pspSpec.ForbiddenSysctls = nil
}
if !utilfeature.DefaultFeatureGate.Enabled(features.CSIInlineVolume) {
pspSpec.AllowedCSIDrivers = nil
}
}
func allowedProcMountTypesInUse(oldPSPSpec *policy.PodSecurityPolicySpec) bool {

View File

@ -120,6 +120,10 @@ func VisitPodSecretNames(pod *v1.Pod, visitor Visitor) bool {
if source.StorageOS.SecretRef != nil && !visitor(source.StorageOS.SecretRef.Name) {
return false
}
case source.CSI != nil:
if source.CSI.NodePublishSecretRef != nil && !visitor(source.CSI.NodePublishSecretRef.Name) {
return false
}
}
}
return true

View File

@ -268,7 +268,11 @@ func TestPodSecrets(t *testing.T) {
VolumeSource: v1.VolumeSource{
StorageOS: &v1.StorageOSVolumeSource{
SecretRef: &v1.LocalObjectReference{
Name: "Spec.Volumes[*].VolumeSource.StorageOS.SecretRef"}}}}},
Name: "Spec.Volumes[*].VolumeSource.StorageOS.SecretRef"}}}}, {
VolumeSource: v1.VolumeSource{
CSI: &v1.CSIVolumeSource{
NodePublishSecretRef: &v1.LocalObjectReference{
Name: "Spec.Volumes[*].VolumeSource.CSI.NodePublishSecretRef"}}}}},
},
}
extractedNames := sets.NewString()
@ -300,6 +304,7 @@ func TestPodSecrets(t *testing.T) {
"Spec.Volumes[*].VolumeSource.ScaleIO.SecretRef",
"Spec.Volumes[*].VolumeSource.ISCSI.SecretRef",
"Spec.Volumes[*].VolumeSource.StorageOS.SecretRef",
"Spec.Volumes[*].VolumeSource.CSI.NodePublishSecretRef",
)
secretPaths := collectResourcePaths(t, "secret", nil, "", reflect.TypeOf(&v1.Pod{}))
secretPaths = secretPaths.Difference(excludedSecretPaths)

View File

@ -154,6 +154,9 @@ type VolumeSource struct {
// StorageOS represents a StorageOS volume that is attached to the kubelet's host machine and mounted into the pod
// +optional
StorageOS *StorageOSVolumeSource
// CSI (Container Storage Interface) represents storage that is handled by an external CSI driver (Alpha feature).
// +optional
CSI *CSIVolumeSource
}
// Similar to VolumeSource but meant for the administrator who creates PVs.
@ -229,7 +232,7 @@ type PersistentVolumeSource struct {
// More info: https://releases.k8s.io/HEAD/examples/volumes/storageos/README.md
// +optional
StorageOS *StorageOSPersistentVolumeSource
// CSI (Container Storage Interface) represents storage that handled by an external CSI driver.
// CSI (Container Storage Interface) represents storage that is handled by an external CSI driver.
// +optional
CSI *CSIPersistentVolumeSource
}
@ -1603,6 +1606,38 @@ type CSIPersistentVolumeSource struct {
NodePublishSecretRef *SecretReference
}
// Represents a source location of a volume to mount, managed by an external CSI driver
type CSIVolumeSource struct {
// Driver is the name of the CSI driver that handles this volume.
// Consult with your admin for the correct name as registered in the cluster.
// Required.
Driver string
// Specifies a read-only configuration for the volume.
// Defaults to false (read/write).
// +optional
ReadOnly *bool
// Filesystem type to mount. Ex. "ext4", "xfs", "ntfs".
// If not provided, the empty value is passed to the associated CSI driver
// which will determine the default filesystem to apply.
// +optional
FSType *string
// VolumeAttributes stores driver-specific properties that are passed to the CSI
// driver. Consult your driver's documentation for supported values.
// +optional
VolumeAttributes map[string]string
// NodePublishSecretRef is a reference to the secret object containing
// sensitive information to pass to the CSI driver to complete the CSI
// NodePublishVolume and NodeUnpublishVolume calls.
// This field is optional, and may be empty if no secret is required. If the
// secret object contains more than one secret, all secret references are passed.
// +optional
NodePublishSecretRef *LocalObjectReference
}
// ContainerPort represents a network port in a single container
type ContainerPort struct {
// Optional: If specified, this must be an IANA_SVC_NAME Each named port

View File

@ -130,6 +130,16 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*v1.CSIVolumeSource)(nil), (*core.CSIVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1_CSIVolumeSource_To_core_CSIVolumeSource(a.(*v1.CSIVolumeSource), b.(*core.CSIVolumeSource), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*core.CSIVolumeSource)(nil), (*v1.CSIVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_core_CSIVolumeSource_To_v1_CSIVolumeSource(a.(*core.CSIVolumeSource), b.(*v1.CSIVolumeSource), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*v1.Capabilities)(nil), (*core.Capabilities)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1_Capabilities_To_core_Capabilities(a.(*v1.Capabilities), b.(*core.Capabilities), scope)
}); err != nil {
@ -2330,6 +2340,34 @@ func Convert_core_CSIPersistentVolumeSource_To_v1_CSIPersistentVolumeSource(in *
return autoConvert_core_CSIPersistentVolumeSource_To_v1_CSIPersistentVolumeSource(in, out, s)
}
func autoConvert_v1_CSIVolumeSource_To_core_CSIVolumeSource(in *v1.CSIVolumeSource, out *core.CSIVolumeSource, s conversion.Scope) error {
out.Driver = in.Driver
out.ReadOnly = (*bool)(unsafe.Pointer(in.ReadOnly))
out.FSType = (*string)(unsafe.Pointer(in.FSType))
out.VolumeAttributes = *(*map[string]string)(unsafe.Pointer(&in.VolumeAttributes))
out.NodePublishSecretRef = (*core.LocalObjectReference)(unsafe.Pointer(in.NodePublishSecretRef))
return nil
}
// Convert_v1_CSIVolumeSource_To_core_CSIVolumeSource is an autogenerated conversion function.
func Convert_v1_CSIVolumeSource_To_core_CSIVolumeSource(in *v1.CSIVolumeSource, out *core.CSIVolumeSource, s conversion.Scope) error {
return autoConvert_v1_CSIVolumeSource_To_core_CSIVolumeSource(in, out, s)
}
func autoConvert_core_CSIVolumeSource_To_v1_CSIVolumeSource(in *core.CSIVolumeSource, out *v1.CSIVolumeSource, s conversion.Scope) error {
out.Driver = in.Driver
out.ReadOnly = (*bool)(unsafe.Pointer(in.ReadOnly))
out.FSType = (*string)(unsafe.Pointer(in.FSType))
out.VolumeAttributes = *(*map[string]string)(unsafe.Pointer(&in.VolumeAttributes))
out.NodePublishSecretRef = (*v1.LocalObjectReference)(unsafe.Pointer(in.NodePublishSecretRef))
return nil
}
// Convert_core_CSIVolumeSource_To_v1_CSIVolumeSource is an autogenerated conversion function.
func Convert_core_CSIVolumeSource_To_v1_CSIVolumeSource(in *core.CSIVolumeSource, out *v1.CSIVolumeSource, s conversion.Scope) error {
return autoConvert_core_CSIVolumeSource_To_v1_CSIVolumeSource(in, out, s)
}
func autoConvert_v1_Capabilities_To_core_Capabilities(in *v1.Capabilities, out *core.Capabilities, s conversion.Scope) error {
out.Add = *(*[]core.Capability)(unsafe.Pointer(&in.Add))
out.Drop = *(*[]core.Capability)(unsafe.Pointer(&in.Drop))
@ -7494,6 +7532,7 @@ func autoConvert_v1_VolumeSource_To_core_VolumeSource(in *v1.VolumeSource, out *
out.PortworxVolume = (*core.PortworxVolumeSource)(unsafe.Pointer(in.PortworxVolume))
out.ScaleIO = (*core.ScaleIOVolumeSource)(unsafe.Pointer(in.ScaleIO))
out.StorageOS = (*core.StorageOSVolumeSource)(unsafe.Pointer(in.StorageOS))
out.CSI = (*core.CSIVolumeSource)(unsafe.Pointer(in.CSI))
return nil
}
@ -7538,6 +7577,7 @@ func autoConvert_core_VolumeSource_To_v1_VolumeSource(in *core.VolumeSource, out
out.PortworxVolume = (*v1.PortworxVolumeSource)(unsafe.Pointer(in.PortworxVolume))
out.ScaleIO = (*v1.ScaleIOVolumeSource)(unsafe.Pointer(in.ScaleIO))
out.StorageOS = (*v1.StorageOSVolumeSource)(unsafe.Pointer(in.StorageOS))
out.CSI = (*v1.CSIVolumeSource)(unsafe.Pointer(in.CSI))
return nil
}

View File

@ -626,6 +626,14 @@ func validateVolumeSource(source *core.VolumeSource, fldPath *field.Path, volNam
allErrs = append(allErrs, validateScaleIOVolumeSource(source.ScaleIO, fldPath.Child("scaleIO"))...)
}
}
if source.CSI != nil {
if numVolumes > 0 {
allErrs = append(allErrs, field.Forbidden(fldPath.Child("csi"), "may not specify more than 1 volume type"))
} else {
numVolumes++
allErrs = append(allErrs, validateCSIVolumeSource(source.CSI, fldPath.Child("csi"))...)
}
}
if numVolumes == 0 {
allErrs = append(allErrs, field.Required(fldPath, "must specify a volume type"))
@ -1484,16 +1492,20 @@ func validateCSIPersistentVolumeSource(csi *core.CSIPersistentVolumeSource, fldP
}
}
if csi.NodeStageSecretRef != nil {
if len(csi.NodeStageSecretRef.Name) == 0 {
allErrs = append(allErrs, field.Required(fldPath.Child("nodeStageSecretRef", "name"), ""))
return allErrs
}
func validateCSIVolumeSource(csi *core.CSIVolumeSource, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
allErrs = append(allErrs, ValidateCSIDriverName(csi.Driver, fldPath.Child("driver"))...)
if csi.NodePublishSecretRef != nil {
if len(csi.NodePublishSecretRef.Name) == 0 {
allErrs = append(allErrs, field.Required(fldPath.Child("nodePublishSecretRef ", "name"), ""))
} else {
allErrs = append(allErrs, ValidateDNS1123Label(csi.NodeStageSecretRef.Name, fldPath.Child("name"))...)
}
if len(csi.NodeStageSecretRef.Namespace) == 0 {
allErrs = append(allErrs, field.Required(fldPath.Child("nodeStageSecretRef", "namespace"), ""))
} else {
allErrs = append(allErrs, ValidateDNS1123Label(csi.NodeStageSecretRef.Namespace, fldPath.Child("namespace"))...)
for _, msg := range ValidateSecretName(csi.NodePublishSecretRef.Name, false) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), csi.NodePublishSecretRef.Name, msg))
}
}
}

View File

@ -250,6 +250,44 @@ func (in *CSIPersistentVolumeSource) DeepCopy() *CSIPersistentVolumeSource {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CSIVolumeSource) DeepCopyInto(out *CSIVolumeSource) {
*out = *in
if in.ReadOnly != nil {
in, out := &in.ReadOnly, &out.ReadOnly
*out = new(bool)
**out = **in
}
if in.FSType != nil {
in, out := &in.FSType, &out.FSType
*out = new(string)
**out = **in
}
if in.VolumeAttributes != nil {
in, out := &in.VolumeAttributes, &out.VolumeAttributes
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
if in.NodePublishSecretRef != nil {
in, out := &in.NodePublishSecretRef, &out.NodePublishSecretRef
*out = new(LocalObjectReference)
**out = **in
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSIVolumeSource.
func (in *CSIVolumeSource) DeepCopy() *CSIVolumeSource {
if in == nil {
return nil
}
out := new(CSIVolumeSource)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Capabilities) DeepCopyInto(out *Capabilities) {
*out = *in
@ -5368,6 +5406,11 @@ func (in *VolumeSource) DeepCopyInto(out *VolumeSource) {
*out = new(StorageOSVolumeSource)
(*in).DeepCopyInto(*out)
}
if in.CSI != nil {
in, out := &in.CSI, &out.CSI
*out = new(CSIVolumeSource)
(*in).DeepCopyInto(*out)
}
return
}

View File

@ -45,6 +45,16 @@ func init() {
// RegisterConversions adds conversion functions to the given scheme.
// Public to allow building arbitrary schemes.
func RegisterConversions(s *runtime.Scheme) error {
if err := s.AddGeneratedConversionFunc((*v1beta1.AllowedCSIDriver)(nil), (*policy.AllowedCSIDriver)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1beta1_AllowedCSIDriver_To_policy_AllowedCSIDriver(a.(*v1beta1.AllowedCSIDriver), b.(*policy.AllowedCSIDriver), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*policy.AllowedCSIDriver)(nil), (*v1beta1.AllowedCSIDriver)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_policy_AllowedCSIDriver_To_v1beta1_AllowedCSIDriver(a.(*policy.AllowedCSIDriver), b.(*v1beta1.AllowedCSIDriver), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*v1beta1.AllowedFlexVolume)(nil), (*policy.AllowedFlexVolume)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1beta1_AllowedFlexVolume_To_policy_AllowedFlexVolume(a.(*v1beta1.AllowedFlexVolume), b.(*policy.AllowedFlexVolume), scope)
}); err != nil {
@ -738,6 +748,26 @@ func RegisterConversions(s *runtime.Scheme) error {
return nil
}
func autoConvert_v1beta1_AllowedCSIDriver_To_policy_AllowedCSIDriver(in *v1beta1.AllowedCSIDriver, out *policy.AllowedCSIDriver, s conversion.Scope) error {
out.Name = in.Name
return nil
}
// Convert_v1beta1_AllowedCSIDriver_To_policy_AllowedCSIDriver is an autogenerated conversion function.
func Convert_v1beta1_AllowedCSIDriver_To_policy_AllowedCSIDriver(in *v1beta1.AllowedCSIDriver, out *policy.AllowedCSIDriver, s conversion.Scope) error {
return autoConvert_v1beta1_AllowedCSIDriver_To_policy_AllowedCSIDriver(in, out, s)
}
func autoConvert_policy_AllowedCSIDriver_To_v1beta1_AllowedCSIDriver(in *policy.AllowedCSIDriver, out *v1beta1.AllowedCSIDriver, s conversion.Scope) error {
out.Name = in.Name
return nil
}
// Convert_policy_AllowedCSIDriver_To_v1beta1_AllowedCSIDriver is an autogenerated conversion function.
func Convert_policy_AllowedCSIDriver_To_v1beta1_AllowedCSIDriver(in *policy.AllowedCSIDriver, out *v1beta1.AllowedCSIDriver, s conversion.Scope) error {
return autoConvert_policy_AllowedCSIDriver_To_v1beta1_AllowedCSIDriver(in, out, s)
}
func autoConvert_v1beta1_AllowedFlexVolume_To_policy_AllowedFlexVolume(in *v1beta1.AllowedFlexVolume, out *policy.AllowedFlexVolume, s conversion.Scope) error {
out.Driver = in.Driver
return nil
@ -1894,6 +1924,7 @@ func autoConvert_v1beta1_PodSecurityPolicySpec_To_policy_PodSecurityPolicySpec(i
}
out.AllowedHostPaths = *(*[]policy.AllowedHostPath)(unsafe.Pointer(&in.AllowedHostPaths))
out.AllowedFlexVolumes = *(*[]policy.AllowedFlexVolume)(unsafe.Pointer(&in.AllowedFlexVolumes))
out.AllowedCSIDrivers = *(*[]policy.AllowedCSIDriver)(unsafe.Pointer(&in.AllowedCSIDrivers))
out.AllowedUnsafeSysctls = *(*[]string)(unsafe.Pointer(&in.AllowedUnsafeSysctls))
out.ForbiddenSysctls = *(*[]string)(unsafe.Pointer(&in.ForbiddenSysctls))
out.AllowedProcMountTypes = *(*[]core.ProcMountType)(unsafe.Pointer(&in.AllowedProcMountTypes))
@ -1935,6 +1966,7 @@ func autoConvert_policy_PodSecurityPolicySpec_To_v1beta1_PodSecurityPolicySpec(i
}
out.AllowedHostPaths = *(*[]v1beta1.AllowedHostPath)(unsafe.Pointer(&in.AllowedHostPaths))
out.AllowedFlexVolumes = *(*[]v1beta1.AllowedFlexVolume)(unsafe.Pointer(&in.AllowedFlexVolumes))
out.AllowedCSIDrivers = *(*[]v1beta1.AllowedCSIDriver)(unsafe.Pointer(&in.AllowedCSIDrivers))
out.AllowedUnsafeSysctls = *(*[]string)(unsafe.Pointer(&in.AllowedUnsafeSysctls))
out.ForbiddenSysctls = *(*[]string)(unsafe.Pointer(&in.ForbiddenSysctls))
out.AllowedProcMountTypes = *(*[]v1.ProcMountType)(unsafe.Pointer(&in.AllowedProcMountTypes))

View File

@ -213,6 +213,10 @@ type PodSecurityPolicySpec struct {
// is allowed in the "Volumes" field.
// +optional
AllowedFlexVolumes []AllowedFlexVolume
// AllowedCSIDrivers is a whitelist of inline CSI drivers that must be explicitly set to be embedded within a pod spec.
// An empty value means no CSI drivers can run inline within a pod spec.
// +optional
AllowedCSIDrivers []AllowedCSIDriver
// AllowedUnsafeSysctls is a list of explicitly allowed unsafe sysctls, defaults to none.
// Each entry is either a plain sysctl name or ends in "*" in which case it is considered
// as a prefix of allowed sysctls. Single * means all unsafe sysctls are allowed.
@ -308,6 +312,12 @@ type AllowedFlexVolume struct {
Driver string
}
// AllowedCSIDriver represents a single inline CSI Driver that is allowed to be used.
type AllowedCSIDriver struct {
// Name is the registered name of the CSI driver
Name string
}
// SELinuxStrategyOptions defines the strategy type and any options used to create the strategy.
type SELinuxStrategyOptions struct {
// Rule is the strategy that will dictate the allowable labels that may be set.

View File

@ -40,6 +40,16 @@ func init() {
// RegisterConversions adds conversion functions to the given scheme.
// Public to allow building arbitrary schemes.
func RegisterConversions(s *runtime.Scheme) error {
if err := s.AddGeneratedConversionFunc((*v1beta1.AllowedCSIDriver)(nil), (*policy.AllowedCSIDriver)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1beta1_AllowedCSIDriver_To_policy_AllowedCSIDriver(a.(*v1beta1.AllowedCSIDriver), b.(*policy.AllowedCSIDriver), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*policy.AllowedCSIDriver)(nil), (*v1beta1.AllowedCSIDriver)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_policy_AllowedCSIDriver_To_v1beta1_AllowedCSIDriver(a.(*policy.AllowedCSIDriver), b.(*v1beta1.AllowedCSIDriver), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*v1beta1.AllowedFlexVolume)(nil), (*policy.AllowedFlexVolume)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1beta1_AllowedFlexVolume_To_policy_AllowedFlexVolume(a.(*v1beta1.AllowedFlexVolume), b.(*policy.AllowedFlexVolume), scope)
}); err != nil {
@ -213,6 +223,26 @@ func RegisterConversions(s *runtime.Scheme) error {
return nil
}
func autoConvert_v1beta1_AllowedCSIDriver_To_policy_AllowedCSIDriver(in *v1beta1.AllowedCSIDriver, out *policy.AllowedCSIDriver, s conversion.Scope) error {
out.Name = in.Name
return nil
}
// Convert_v1beta1_AllowedCSIDriver_To_policy_AllowedCSIDriver is an autogenerated conversion function.
func Convert_v1beta1_AllowedCSIDriver_To_policy_AllowedCSIDriver(in *v1beta1.AllowedCSIDriver, out *policy.AllowedCSIDriver, s conversion.Scope) error {
return autoConvert_v1beta1_AllowedCSIDriver_To_policy_AllowedCSIDriver(in, out, s)
}
func autoConvert_policy_AllowedCSIDriver_To_v1beta1_AllowedCSIDriver(in *policy.AllowedCSIDriver, out *v1beta1.AllowedCSIDriver, s conversion.Scope) error {
out.Name = in.Name
return nil
}
// Convert_policy_AllowedCSIDriver_To_v1beta1_AllowedCSIDriver is an autogenerated conversion function.
func Convert_policy_AllowedCSIDriver_To_v1beta1_AllowedCSIDriver(in *policy.AllowedCSIDriver, out *v1beta1.AllowedCSIDriver, s conversion.Scope) error {
return autoConvert_policy_AllowedCSIDriver_To_v1beta1_AllowedCSIDriver(in, out, s)
}
func autoConvert_v1beta1_AllowedFlexVolume_To_policy_AllowedFlexVolume(in *v1beta1.AllowedFlexVolume, out *policy.AllowedFlexVolume, s conversion.Scope) error {
out.Driver = in.Driver
return nil
@ -549,6 +579,7 @@ func autoConvert_v1beta1_PodSecurityPolicySpec_To_policy_PodSecurityPolicySpec(i
}
out.AllowedHostPaths = *(*[]policy.AllowedHostPath)(unsafe.Pointer(&in.AllowedHostPaths))
out.AllowedFlexVolumes = *(*[]policy.AllowedFlexVolume)(unsafe.Pointer(&in.AllowedFlexVolumes))
out.AllowedCSIDrivers = *(*[]policy.AllowedCSIDriver)(unsafe.Pointer(&in.AllowedCSIDrivers))
out.AllowedUnsafeSysctls = *(*[]string)(unsafe.Pointer(&in.AllowedUnsafeSysctls))
out.ForbiddenSysctls = *(*[]string)(unsafe.Pointer(&in.ForbiddenSysctls))
out.AllowedProcMountTypes = *(*[]core.ProcMountType)(unsafe.Pointer(&in.AllowedProcMountTypes))
@ -590,6 +621,7 @@ func autoConvert_policy_PodSecurityPolicySpec_To_v1beta1_PodSecurityPolicySpec(i
}
out.AllowedHostPaths = *(*[]v1beta1.AllowedHostPath)(unsafe.Pointer(&in.AllowedHostPaths))
out.AllowedFlexVolumes = *(*[]v1beta1.AllowedFlexVolume)(unsafe.Pointer(&in.AllowedFlexVolumes))
out.AllowedCSIDrivers = *(*[]v1beta1.AllowedCSIDriver)(unsafe.Pointer(&in.AllowedCSIDrivers))
out.AllowedUnsafeSysctls = *(*[]string)(unsafe.Pointer(&in.AllowedUnsafeSysctls))
out.ForbiddenSysctls = *(*[]string)(unsafe.Pointer(&in.ForbiddenSysctls))
out.AllowedProcMountTypes = *(*[]corev1.ProcMountType)(unsafe.Pointer(&in.AllowedProcMountTypes))

View File

@ -121,6 +121,7 @@ func ValidatePodSecurityPolicySpec(spec *policy.PodSecurityPolicySpec, fldPath *
allErrs = append(allErrs, validatePSPAllowedProcMountTypes(fldPath.Child("allowedProcMountTypes"), spec.AllowedProcMountTypes)...)
allErrs = append(allErrs, validatePSPAllowedHostPaths(fldPath.Child("allowedHostPaths"), spec.AllowedHostPaths)...)
allErrs = append(allErrs, validatePSPAllowedFlexVolumes(fldPath.Child("allowedFlexVolumes"), spec.AllowedFlexVolumes)...)
allErrs = append(allErrs, validatePSPAllowedCSIDrivers(fldPath.Child("allowedCSIDrivers"), spec.AllowedCSIDrivers)...)
allErrs = append(allErrs, validatePodSecurityPolicySysctls(fldPath.Child("allowedUnsafeSysctls"), spec.AllowedUnsafeSysctls)...)
allErrs = append(allErrs, validatePodSecurityPolicySysctls(fldPath.Child("forbiddenSysctls"), spec.ForbiddenSysctls)...)
allErrs = append(allErrs, validatePodSecurityPolicySysctlListsDoNotOverlap(fldPath.Child("allowedUnsafeSysctls"), fldPath.Child("forbiddenSysctls"), spec.AllowedUnsafeSysctls, spec.ForbiddenSysctls)...)
@ -194,6 +195,17 @@ func validatePSPAllowedFlexVolumes(fldPath *field.Path, flexVolumes []policy.All
return allErrs
}
func validatePSPAllowedCSIDrivers(fldPath *field.Path, csiDrivers []policy.AllowedCSIDriver) field.ErrorList {
allErrs := field.ErrorList{}
if len(csiDrivers) > 0 {
for idx, csiDriver := range csiDrivers {
fieldPath := fldPath.Child("allowedCSIDriver").Index(idx).Child("name")
allErrs = append(allErrs, apivalidation.ValidateCSIDriverName(csiDriver.Name, fieldPath)...)
}
}
return allErrs
}
// validatePSPSELinux validates the SELinux fields of PodSecurityPolicy.
func validatePSPSELinux(fldPath *field.Path, seLinux *policy.SELinuxStrategyOptions) field.ErrorList {
allErrs := field.ErrorList{}

View File

@ -27,6 +27,22 @@ import (
core "k8s.io/kubernetes/pkg/apis/core"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *AllowedCSIDriver) DeepCopyInto(out *AllowedCSIDriver) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AllowedCSIDriver.
func (in *AllowedCSIDriver) DeepCopy() *AllowedCSIDriver {
if in == nil {
return nil
}
out := new(AllowedCSIDriver)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *AllowedFlexVolume) DeepCopyInto(out *AllowedFlexVolume) {
*out = *in
@ -370,6 +386,11 @@ func (in *PodSecurityPolicySpec) DeepCopyInto(out *PodSecurityPolicySpec) {
*out = make([]AllowedFlexVolume, len(*in))
copy(*out, *in)
}
if in.AllowedCSIDrivers != nil {
in, out := &in.AllowedCSIDrivers, &out.AllowedCSIDrivers
*out = make([]AllowedCSIDriver, len(*in))
copy(*out, *in)
}
if in.AllowedUnsafeSysctls != nil {
in, out := &in.AllowedUnsafeSysctls, &out.AllowedUnsafeSysctls
*out = make([]string, len(*in))

View File

@ -348,6 +348,12 @@ const (
// Enables CSI to use raw block storage volumes
CSIBlockVolume utilfeature.Feature = "CSIBlockVolume"
// owner: @vladimirvivien
// alpha: v1.14
//
// Enables CSI Inline volumes support for pods
CSIInlineVolume utilfeature.Feature = "CSIInlineVolume"
// owner: @tallclair
// alpha: v1.12
//
@ -491,6 +497,7 @@ var defaultKubernetesFeatureGates = map[utilfeature.Feature]utilfeature.FeatureS
KubeletPluginsWatcher: {Default: true, PreRelease: utilfeature.GA, LockToDefault: true}, // remove in 1.16
ResourceQuotaScopeSelectors: {Default: true, PreRelease: utilfeature.Beta},
CSIBlockVolume: {Default: true, PreRelease: utilfeature.Beta},
CSIInlineVolume: {Default: false, PreRelease: utilfeature.Alpha},
RuntimeClass: {Default: false, PreRelease: utilfeature.Alpha},
NodeLease: {Default: true, PreRelease: utilfeature.Beta},
SCTPSupport: {Default: false, PreRelease: utilfeature.Alpha},

View File

@ -129,6 +129,8 @@ func GetVolumeFSType(v api.Volume) (policy.FSType, error) {
return policy.PortworxVolume, nil
case v.ScaleIO != nil:
return policy.ScaleIO, nil
case v.CSI != nil:
return policy.CSI, nil
}
return "", fmt.Errorf("unknown volume type for volume: %#v", v)

View File

@ -63,15 +63,15 @@ func (c *csiAttacher) Attach(spec *volume.Spec, nodeName types.NodeName) (string
return "", errors.New("missing spec")
}
csiSource, err := getCSISourceFromSpec(spec)
pvSrc, err := getPVSourceFromSpec(spec)
if err != nil {
klog.Error(log("attacher.Attach failed to get CSI persistent source: %v", err))
klog.Error(log("attacher.Attach failed to get CSIPersistentVolumeSource: %v", err))
return "", err
}
node := string(nodeName)
pvName := spec.PersistentVolume.GetName()
attachID := getAttachmentName(csiSource.VolumeHandle, csiSource.Driver, node)
attachID := getAttachmentName(pvSrc.VolumeHandle, pvSrc.Driver, node)
attachment := &storage.VolumeAttachment{
ObjectMeta: meta.ObjectMeta{
@ -79,7 +79,7 @@ func (c *csiAttacher) Attach(spec *volume.Spec, nodeName types.NodeName) (string
},
Spec: storage.VolumeAttachmentSpec{
NodeName: node,
Attacher: csiSource.Driver,
Attacher: pvSrc.Driver,
Source: storage.VolumeAttachmentSource{
PersistentVolumeName: &pvName,
},
@ -97,12 +97,12 @@ func (c *csiAttacher) Attach(spec *volume.Spec, nodeName types.NodeName) (string
}
if alreadyExist {
klog.V(4).Info(log("attachment [%v] for volume [%v] already exists (will not be recreated)", attachID, csiSource.VolumeHandle))
klog.V(4).Info(log("attachment [%v] for volume [%v] already exists (will not be recreated)", attachID, pvSrc.VolumeHandle))
} else {
klog.V(4).Info(log("attachment [%v] for volume [%v] created successfully", attachID, csiSource.VolumeHandle))
klog.V(4).Info(log("attachment [%v] for volume [%v] created successfully", attachID, pvSrc.VolumeHandle))
}
if _, err := c.waitForVolumeAttachment(csiSource.VolumeHandle, attachID, csiTimeout); err != nil {
if _, err := c.waitForVolumeAttachment(pvSrc.VolumeHandle, attachID, csiTimeout); err != nil {
return "", err
}
@ -113,7 +113,7 @@ func (c *csiAttacher) Attach(spec *volume.Spec, nodeName types.NodeName) (string
}
func (c *csiAttacher) WaitForAttach(spec *volume.Spec, _ string, pod *v1.Pod, timeout time.Duration) (string, error) {
source, err := getCSISourceFromSpec(spec)
source, err := getPVSourceFromSpec(spec)
if err != nil {
klog.Error(log("attacher.WaitForAttach failed to extract CSI volume source: %v", err))
return "", err
@ -220,14 +220,18 @@ func (c *csiAttacher) VolumesAreAttached(specs []*volume.Spec, nodeName types.No
klog.Error(log("attacher.VolumesAreAttached missing volume.Spec"))
return nil, errors.New("missing spec")
}
source, err := getCSISourceFromSpec(spec)
pvSrc, err := getPVSourceFromSpec(spec)
if err != nil {
klog.Error(log("attacher.VolumesAreAttached failed: %v", err))
attached[spec] = false
klog.Error(log("attacher.VolumesAreAttached failed to get CSIPersistentVolumeSource: %v", err))
continue
}
skip, err := c.plugin.skipAttach(source.Driver)
driverName := pvSrc.Driver
volumeHandle := pvSrc.VolumeHandle
skip, err := c.plugin.skipAttach(driverName)
if err != nil {
klog.Error(log("Failed to check CSIDriver for %s: %s", source.Driver, err))
klog.Error(log("Failed to check CSIDriver for %s: %s", driverName, err))
} else {
if skip {
// This volume is not attachable, pretend it's attached
@ -236,7 +240,7 @@ func (c *csiAttacher) VolumesAreAttached(specs []*volume.Spec, nodeName types.No
}
}
attachID := getAttachmentName(source.VolumeHandle, source.Driver, string(nodeName))
attachID := getAttachmentName(volumeHandle, driverName, string(nodeName))
klog.V(4).Info(log("probing attachment status for VolumeAttachment %v", attachID))
attach, err := c.k8s.StorageV1().VolumeAttachments().Get(attachID, meta.GetOptions{})
if err != nil {
@ -285,9 +289,9 @@ func (c *csiAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMo
if spec == nil {
return fmt.Errorf("attacher.MountDevice failed, spec is nil")
}
csiSource, err := getCSISourceFromSpec(spec)
csiSource, err := getPVSourceFromSpec(spec)
if err != nil {
klog.Error(log("attacher.MountDevice failed to get CSI persistent source: %v", err))
klog.Error(log("attacher.MountDevice failed to get CSIPersistentVolumeSource: %v", err))
return err
}

View File

@ -37,7 +37,6 @@ import (
fakeclient "k8s.io/client-go/kubernetes/fake"
core "k8s.io/client-go/testing"
utiltesting "k8s.io/client-go/util/testing"
"k8s.io/klog"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/volume"
volumetest "k8s.io/kubernetes/pkg/volume/testing"
@ -84,16 +83,17 @@ func markVolumeAttached(t *testing.T, client clientset.Interface, watch *watch.R
t.Error(err)
}
if attach != nil {
klog.Infof("stopping wait")
t.Logf("attachment found on try %d, stopping wait...", i)
break
}
}
klog.Infof("stopped wait")
t.Logf("stopped waiting for attachment")
if attach == nil {
t.Logf("attachment not found for id:%v", attachID)
} else {
attach.Status = status
t.Logf("updating attachment %s with attach status %v", attachID, status)
_, err := client.StorageV1().VolumeAttachments().Update(attach)
if err != nil {
t.Error(err)
@ -103,13 +103,13 @@ func markVolumeAttached(t *testing.T, client clientset.Interface, watch *watch.R
}
func TestAttacherAttach(t *testing.T) {
testCases := []struct {
name string
nodeName string
driverName string
volumeName string
attachID string
spec *volume.Spec
injectAttacherError bool
shouldFail bool
}{
@ -119,6 +119,7 @@ func TestAttacherAttach(t *testing.T) {
driverName: "testdriver-01",
volumeName: "testvol-01",
attachID: getAttachmentName("testvol-01", "testdriver-01", "testnode-01"),
spec: volume.NewSpecFromPersistentVolume(makeTestPV("pv01", 10, "testdriver-01", "testvol-01"), false),
},
{
name: "test ok 2",
@ -126,6 +127,7 @@ func TestAttacherAttach(t *testing.T) {
driverName: "driver02",
volumeName: "vol02",
attachID: getAttachmentName("vol02", "driver02", "node02"),
spec: volume.NewSpecFromPersistentVolume(makeTestPV("pv01", 10, "driver02", "vol02"), false),
},
{
name: "mismatch vol",
@ -133,6 +135,7 @@ func TestAttacherAttach(t *testing.T) {
driverName: "driver02",
volumeName: "vol01",
attachID: getAttachmentName("vol02", "driver02", "node02"),
spec: volume.NewSpecFromPersistentVolume(makeTestPV("pv01", 10, "driver02", "vol01"), false),
shouldFail: true,
},
{
@ -141,6 +144,7 @@ func TestAttacherAttach(t *testing.T) {
driverName: "driver000",
volumeName: "vol02",
attachID: getAttachmentName("vol02", "driver02", "node02"),
spec: volume.NewSpecFromPersistentVolume(makeTestPV("pv01", 10, "driver01", "vol02"), false),
shouldFail: true,
},
{
@ -149,6 +153,7 @@ func TestAttacherAttach(t *testing.T) {
driverName: "driver000",
volumeName: "vol02",
attachID: getAttachmentName("vol02", "driver02", "node02"),
spec: volume.NewSpecFromPersistentVolume(makeTestPV("pv01", 10, "driver02", "vol02"), false),
shouldFail: true,
},
{
@ -157,13 +162,31 @@ func TestAttacherAttach(t *testing.T) {
driverName: "driver02",
volumeName: "vol02",
attachID: getAttachmentName("vol02", "driver02", "node02"),
spec: volume.NewSpecFromPersistentVolume(makeTestPV("pv01", 10, "driver02", "vol02"), false),
injectAttacherError: true,
shouldFail: true,
},
{
name: "test with volume source",
nodeName: "node000",
driverName: "driver000",
volumeName: "vol02",
attachID: getAttachmentName("vol02", "driver02", "node02"),
spec: volume.NewSpecFromVolume(makeTestVol("pv01", "driver02")),
shouldFail: true, // csi not enabled
},
{
name: "missing spec",
nodeName: "node000",
driverName: "driver000",
volumeName: "vol02",
attachID: getAttachmentName("vol02", "driver02", "node02"),
shouldFail: true, // csi not enabled
},
}
// attacher loop
for i, tc := range testCases {
for _, tc := range testCases {
t.Logf("test case: %s", tc.name)
plug, fakeWatcher, tmpDir, _ := newTestWatchPlugin(t, nil)
defer os.RemoveAll(tmpDir)
@ -175,9 +198,7 @@ func TestAttacherAttach(t *testing.T) {
csiAttacher := attacher.(*csiAttacher)
spec := volume.NewSpecFromPersistentVolume(makeTestPV(fmt.Sprintf("test-pv%d", i), 10, tc.driverName, tc.volumeName), false)
go func(id, nodename string, fail bool) {
go func(spec *volume.Spec, id, nodename string, fail bool) {
attachID, err := csiAttacher.Attach(spec, types.NodeName(nodename))
if !fail && err != nil {
t.Errorf("expecting no failure, but got err: %v", err)
@ -188,7 +209,83 @@ func TestAttacherAttach(t *testing.T) {
if attachID != id && !fail {
t.Errorf("expecting attachID %v, got %v", id, attachID)
}
}(tc.attachID, tc.nodeName, tc.shouldFail)
}(tc.spec, tc.attachID, tc.nodeName, tc.shouldFail)
var status storage.VolumeAttachmentStatus
if tc.injectAttacherError {
status.Attached = false
status.AttachError = &storage.VolumeError{
Message: "attacher error",
}
} else {
status.Attached = true
}
markVolumeAttached(t, csiAttacher.k8s, fakeWatcher, tc.attachID, status)
}
}
func TestAttacherAttachWithInline(t *testing.T) {
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIInlineVolume, true)()
testCases := []struct {
name string
nodeName string
driverName string
volumeName string
attachID string
spec *volume.Spec
injectAttacherError bool
shouldFail bool
}{
{
name: "test ok 1 with PV",
nodeName: "node01",
attachID: getAttachmentName("vol01", "driver01", "node01"),
spec: volume.NewSpecFromPersistentVolume(makeTestPV("pv01", 10, "driver01", "vol01"), false),
},
{
name: "test failure, attach with volSrc",
nodeName: "node01",
attachID: getAttachmentName("vol01", "driver01", "node01"),
spec: volume.NewSpecFromVolume(makeTestVol("vol01", "driver01")),
shouldFail: true,
},
{
name: "attacher error",
nodeName: "node02",
attachID: getAttachmentName("vol02", "driver02", "node02"),
spec: volume.NewSpecFromPersistentVolume(makeTestPV("pv02", 10, "driver02", "vol02"), false),
injectAttacherError: true,
shouldFail: true,
},
{
name: "missing spec",
nodeName: "node02",
attachID: getAttachmentName("vol02", "driver02", "node02"),
shouldFail: true,
},
}
// attacher loop
for _, tc := range testCases {
t.Logf("test case: %s", tc.name)
plug, fakeWatcher, tmpDir, _ := newTestWatchPlugin(t, nil)
defer os.RemoveAll(tmpDir)
attacher, err := plug.NewAttacher()
if err != nil {
t.Fatalf("failed to create new attacher: %v", err)
}
csiAttacher := attacher.(*csiAttacher)
go func(spec *volume.Spec, id, nodename string, fail bool) {
attachID, err := csiAttacher.Attach(spec, types.NodeName(nodename))
if fail != (err != nil) {
t.Errorf("expecting no failure, but got err: %v", err)
}
if attachID != id && !fail {
t.Errorf("expecting attachID %v, got %v", id, attachID)
}
}(tc.spec, tc.attachID, tc.nodeName, tc.shouldFail)
var status storage.VolumeAttachmentStatus
if tc.injectAttacherError {
@ -260,23 +357,25 @@ func TestAttacherWithCSIDriver(t *testing.T) {
return
}
expectedAttachID := getAttachmentName("test-vol", test.driver, "node")
status := storage.VolumeAttachmentStatus{
Attached: true,
}
if test.expectVolumeAttachment {
go markVolumeAttached(t, csiAttacher.k8s, fakeWatcher, expectedAttachID, status)
}
go func(volSpec *volume.Spec, expectAttach bool) {
attachID, err := csiAttacher.Attach(volSpec, types.NodeName("node"))
if err != nil {
t.Errorf("Attach() failed: %s", err)
}
if expectAttach && attachID == "" {
t.Errorf("Expected attachID, got nothing")
}
if !expectAttach && attachID != "" {
t.Errorf("Expected empty attachID, got %q", attachID)
}
}(spec, test.expectVolumeAttachment)
attachID, err := csiAttacher.Attach(spec, types.NodeName("node"))
if err != nil {
t.Errorf("Attach() failed: %s", err)
}
if test.expectVolumeAttachment && attachID == "" {
t.Errorf("Expected attachID, got nothing")
}
if !test.expectVolumeAttachment && attachID != "" {
t.Errorf("Expected empty attachID, got %q", attachID)
if test.expectVolumeAttachment {
expectedAttachID := getAttachmentName("test-vol", test.driver, "node")
status := storage.VolumeAttachmentStatus{
Attached: true,
}
markVolumeAttached(t, csiAttacher.k8s, fakeWatcher, expectedAttachID, status)
}
})
}
@ -354,6 +453,7 @@ func TestAttacherWaitForAttach(t *testing.T) {
name string
driver string
makeAttachment func() *storage.VolumeAttachment
spec *volume.Spec
expectedAttachID string
expectError bool
}{
@ -367,9 +467,22 @@ func TestAttacherWaitForAttach(t *testing.T) {
successfulAttachment.Status.Attached = true
return successfulAttachment
},
spec: volume.NewSpecFromPersistentVolume(makeTestPV("test-pv", 10, "attachable", "test-vol"), false),
expectedAttachID: getAttachmentName("test-vol", "attachable", "node"),
expectError: false,
},
{
name: "failed attach with vol source",
makeAttachment: func() *storage.VolumeAttachment {
testAttachID := getAttachmentName("test-vol", "attachable", "node")
successfulAttachment := makeTestAttachment(testAttachID, "node", "volSrc01")
successfulAttachment.Status.Attached = true
return successfulAttachment
},
spec: volume.NewSpecFromVolume(makeTestVol("volSrc01", "attachable")),
expectError: true,
},
{
name: "failed attach",
driver: "attachable",
@ -387,7 +500,6 @@ func TestAttacherWaitForAttach(t *testing.T) {
t.Fatalf("failed to create new attacher: %v", err)
}
csiAttacher := attacher.(*csiAttacher)
spec := volume.NewSpecFromPersistentVolume(makeTestPV("test-pv", 10, test.driver, "test-vol"), false)
if test.makeAttachment != nil {
attachment := test.makeAttachment()
@ -402,7 +514,7 @@ func TestAttacherWaitForAttach(t *testing.T) {
t.Logf("created test VolumeAttachment %+v", gotAttachment)
}
attachID, err := csiAttacher.WaitForAttach(spec, "", nil, time.Second)
attachID, err := csiAttacher.WaitForAttach(test.spec, "", nil, time.Second)
if err != nil && !test.expectError {
t.Errorf("Unexpected error: %s", err)
}
@ -416,6 +528,86 @@ func TestAttacherWaitForAttach(t *testing.T) {
}
}
func TestAttacherWaitForAttachWithInline(t *testing.T) {
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIInlineVolume, true)()
tests := []struct {
name string
driver string
makeAttachment func() *storage.VolumeAttachment
spec *volume.Spec
expectedAttachID string
expectError bool
}{
{
name: "successful attach with PV",
makeAttachment: func() *storage.VolumeAttachment {
testAttachID := getAttachmentName("test-vol", "attachable", "node")
successfulAttachment := makeTestAttachment(testAttachID, "node", "test-pv")
successfulAttachment.Status.Attached = true
return successfulAttachment
},
spec: volume.NewSpecFromPersistentVolume(makeTestPV("test-pv", 10, "attachable", "test-vol"), false),
expectedAttachID: getAttachmentName("test-vol", "attachable", "node"),
expectError: false,
},
{
name: "failed attach with volSrc",
makeAttachment: func() *storage.VolumeAttachment {
testAttachID := getAttachmentName("test-vol", "attachable", "node")
successfulAttachment := makeTestAttachment(testAttachID, "node", "volSrc01")
successfulAttachment.Status.Attached = true
return successfulAttachment
},
spec: volume.NewSpecFromVolume(makeTestVol("volSrc01", "attachable")),
expectError: true,
},
{
name: "failed attach",
driver: "non-attachable",
spec: volume.NewSpecFromPersistentVolume(makeTestPV("test-pv", 10, "non-attachable", "test-vol"), false),
expectError: true,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
plug, _, tmpDir, _ := newTestWatchPlugin(t, nil)
defer os.RemoveAll(tmpDir)
attacher, err := plug.NewAttacher()
if err != nil {
t.Fatalf("failed to create new attacher: %v", err)
}
csiAttacher := attacher.(*csiAttacher)
if test.makeAttachment != nil {
attachment := test.makeAttachment()
_, err = csiAttacher.k8s.StorageV1().VolumeAttachments().Create(attachment)
if err != nil {
t.Fatalf("failed to create VolumeAttachment: %v", err)
}
gotAttachment, err := csiAttacher.k8s.StorageV1().VolumeAttachments().Get(attachment.Name, meta.GetOptions{})
if err != nil {
t.Fatalf("failed to get created VolumeAttachment: %v", err)
}
t.Logf("created test VolumeAttachment %+v", gotAttachment)
}
attachID, err := csiAttacher.WaitForAttach(test.spec, "", nil, time.Second)
if test.expectError != (err != nil) {
t.Errorf("Unexpected error: %s", err)
return
}
if attachID != test.expectedAttachID {
t.Errorf("Expected attachID %q, got %q", test.expectedAttachID, attachID)
}
})
}
}
func TestAttacherWaitForVolumeAttachment(t *testing.T) {
nodeName := "test-node"
testCases := []struct {
@ -518,60 +710,165 @@ func TestAttacherWaitForVolumeAttachment(t *testing.T) {
}
func TestAttacherVolumesAreAttached(t *testing.T) {
plug, tmpDir := newTestPlugin(t, nil)
defer os.RemoveAll(tmpDir)
attacher, err := plug.NewAttacher()
if err != nil {
t.Fatalf("failed to create new attacher: %v", err)
type attachedSpec struct {
volName string
spec *volume.Spec
attached bool
}
csiAttacher := attacher.(*csiAttacher)
nodeName := "test-node"
testCases := []struct {
name string
attachedStats map[string]bool
attachedSpecs []attachedSpec
}{
{"attach + detach", map[string]bool{"vol-01": true, "vol-02": true, "vol-03": false, "vol-04": false, "vol-05": true}},
{"all detached", map[string]bool{"vol-11": false, "vol-12": false, "vol-13": false, "vol-14": false, "vol-15": false}},
{"all attached", map[string]bool{"vol-21": true, "vol-22": true, "vol-23": true, "vol-24": true, "vol-25": true}},
{
"attach and detach",
[]attachedSpec{
{"vol0", volume.NewSpecFromPersistentVolume(makeTestPV("pv0", 10, testDriver, "vol0"), false), true},
{"vol1", volume.NewSpecFromPersistentVolume(makeTestPV("pv1", 20, testDriver, "vol1"), false), true},
{"vol2", volume.NewSpecFromPersistentVolume(makeTestPV("pv2", 10, testDriver, "vol2"), false), false},
{"vol3", volume.NewSpecFromPersistentVolume(makeTestPV("pv3", 10, testDriver, "vol3"), false), false},
{"vol4", volume.NewSpecFromPersistentVolume(makeTestPV("pv4", 20, testDriver, "vol4"), false), true},
},
},
{
"all detached",
[]attachedSpec{
{"vol0", volume.NewSpecFromPersistentVolume(makeTestPV("pv0", 10, testDriver, "vol0"), false), false},
{"vol1", volume.NewSpecFromPersistentVolume(makeTestPV("pv1", 20, testDriver, "vol1"), false), false},
{"vol2", volume.NewSpecFromPersistentVolume(makeTestPV("pv2", 10, testDriver, "vol2"), false), false},
},
},
{
"all attached",
[]attachedSpec{
{"vol0", volume.NewSpecFromPersistentVolume(makeTestPV("pv0", 10, testDriver, "vol0"), false), true},
{"vol1", volume.NewSpecFromPersistentVolume(makeTestPV("pv1", 20, testDriver, "vol1"), false), true},
},
},
{
"include non-attable",
[]attachedSpec{
{"vol0", volume.NewSpecFromPersistentVolume(makeTestPV("pv0", 10, testDriver, "vol0"), false), true},
{"vol1", volume.NewSpecFromVolume(makeTestVol("pv1", testDriver)), false},
},
},
}
for _, tc := range testCases {
var specs []*volume.Spec
// create and save volume attchments
for volName, stat := range tc.attachedStats {
pv := makeTestPV("test-pv", 10, testDriver, volName)
spec := volume.NewSpecFromPersistentVolume(pv, pv.Spec.PersistentVolumeSource.CSI.ReadOnly)
specs = append(specs, spec)
attachID := getAttachmentName(volName, testDriver, nodeName)
attachment := makeTestAttachment(attachID, nodeName, pv.GetName())
attachment.Status.Attached = stat
_, err := csiAttacher.k8s.StorageV1().VolumeAttachments().Create(attachment)
if err != nil {
t.Fatalf("failed to attach: %v", err)
}
}
t.Run(tc.name, func(t *testing.T) {
plug, tmpDir := newTestPlugin(t, nil)
defer os.RemoveAll(tmpDir)
// retrieve attached status
stats, err := csiAttacher.VolumesAreAttached(specs, types.NodeName(nodeName))
if err != nil {
t.Fatal(err)
}
if len(tc.attachedStats) != len(stats) {
t.Errorf("expecting %d attachment status, got %d", len(tc.attachedStats), len(stats))
}
// compare attachment status for each spec
for spec, stat := range stats {
source, err := getCSISourceFromSpec(spec)
attacher, err := plug.NewAttacher()
if err != nil {
t.Error(err)
t.Fatalf("failed to create new attacher: %v", err)
}
if stat != tc.attachedStats[source.VolumeHandle] {
t.Errorf("expecting volume attachment %t, got %t", tc.attachedStats[source.VolumeHandle], stat)
csiAttacher := attacher.(*csiAttacher)
nodeName := "test-node"
var specs []*volume.Spec
// create and save volume attchments
for _, attachedSpec := range tc.attachedSpecs {
specs = append(specs, attachedSpec.spec)
attachID := getAttachmentName(attachedSpec.volName, testDriver, nodeName)
attachment := makeTestAttachment(attachID, nodeName, attachedSpec.spec.Name())
attachment.Status.Attached = attachedSpec.attached
_, err := csiAttacher.k8s.StorageV1().VolumeAttachments().Create(attachment)
if err != nil {
t.Fatalf("failed to attach: %v", err)
}
}
}
// retrieve attached status
stats, err := csiAttacher.VolumesAreAttached(specs, types.NodeName(nodeName))
if err != nil {
t.Fatal(err)
}
if len(tc.attachedSpecs) != len(stats) {
t.Errorf("expecting %d attachment status, got %d", len(tc.attachedSpecs), len(stats))
}
// compare attachment status for each spec
for _, attached := range tc.attachedSpecs {
stat, ok := stats[attached.spec]
if attached.attached && !ok {
t.Error("failed to retrieve attached status for:", attached.spec)
}
if attached.attached != stat {
t.Errorf("expecting volume attachment %t, got %t", attached.attached, stat)
}
}
})
}
}
func TestAttacherVolumesAreAttachedWithInline(t *testing.T) {
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIInlineVolume, true)()
type attachedSpec struct {
volName string
spec *volume.Spec
attached bool
}
testCases := []struct {
name string
attachedSpecs []attachedSpec
}{
{
"attach and detach with volume sources",
[]attachedSpec{
{"vol0", volume.NewSpecFromPersistentVolume(makeTestPV("pv0", 10, testDriver, "vol0"), false), true},
{"vol1", volume.NewSpecFromVolume(makeTestVol("pv1", testDriver)), false},
{"vol2", volume.NewSpecFromPersistentVolume(makeTestPV("pv2", 10, testDriver, "vol2"), false), true},
{"vol3", volume.NewSpecFromVolume(makeTestVol("pv3", testDriver)), false},
{"vol4", volume.NewSpecFromPersistentVolume(makeTestPV("pv4", 20, testDriver, "vol4"), false), true},
},
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
plug, tmpDir := newTestPlugin(t, nil)
defer os.RemoveAll(tmpDir)
attacher, err := plug.NewAttacher()
if err != nil {
t.Fatalf("failed to create new attacher: %v", err)
}
csiAttacher := attacher.(*csiAttacher)
nodeName := "test-node"
var specs []*volume.Spec
// create and save volume attchments
for _, attachedSpec := range tc.attachedSpecs {
specs = append(specs, attachedSpec.spec)
attachID := getAttachmentName(attachedSpec.volName, testDriver, nodeName)
attachment := makeTestAttachment(attachID, nodeName, attachedSpec.spec.Name())
attachment.Status.Attached = attachedSpec.attached
_, err := csiAttacher.k8s.StorageV1().VolumeAttachments().Create(attachment)
if err != nil {
t.Fatalf("failed to attach: %v", err)
}
}
// retrieve attached status
stats, err := csiAttacher.VolumesAreAttached(specs, types.NodeName(nodeName))
if err != nil {
t.Fatal(err)
}
if len(tc.attachedSpecs) != len(stats) {
t.Errorf("expecting %d attachment status, got %d", len(tc.attachedSpecs), len(stats))
}
// compare attachment status for each spec
for _, attached := range tc.attachedSpecs {
stat, ok := stats[attached.spec]
if attached.attached && !ok {
t.Error("failed to retrieve attached status for:", attached.spec)
}
if attached.attached != stat {
t.Errorf("expecting volume attachment %t, got %t", attached.attached, stat)
}
}
})
}
}
@ -708,6 +1005,7 @@ func TestAttacherGetDeviceMountPath(t *testing.T) {
}
func TestAttacherMountDevice(t *testing.T) {
pvName := "test-pv"
testCases := []struct {
testName string
volName string
@ -715,13 +1013,15 @@ func TestAttacherMountDevice(t *testing.T) {
deviceMountPath string
stageUnstageSet bool
shouldFail bool
spec *volume.Spec
}{
{
testName: "normal",
testName: "normal PV",
volName: "test-vol1",
devicePath: "path1",
deviceMountPath: "path2",
stageUnstageSet: true,
spec: volume.NewSpecFromPersistentVolume(makeTestPV(pvName, 10, testDriver, "test-vol1"), false),
},
{
testName: "no vol name",
@ -730,6 +1030,7 @@ func TestAttacherMountDevice(t *testing.T) {
deviceMountPath: "path2",
stageUnstageSet: true,
shouldFail: true,
spec: volume.NewSpecFromPersistentVolume(makeTestPV(pvName, 10, testDriver, ""), false),
},
{
testName: "no device path",
@ -738,6 +1039,7 @@ func TestAttacherMountDevice(t *testing.T) {
deviceMountPath: "path2",
stageUnstageSet: true,
shouldFail: false,
spec: volume.NewSpecFromPersistentVolume(makeTestPV(pvName, 10, testDriver, "test-vol1"), false),
},
{
testName: "no device mount path",
@ -746,6 +1048,7 @@ func TestAttacherMountDevice(t *testing.T) {
deviceMountPath: "",
stageUnstageSet: true,
shouldFail: true,
spec: volume.NewSpecFromPersistentVolume(makeTestPV(pvName, 10, testDriver, "test-vol1"), false),
},
{
testName: "stage_unstage cap not set",
@ -753,13 +1056,20 @@ func TestAttacherMountDevice(t *testing.T) {
devicePath: "path1",
deviceMountPath: "path2",
stageUnstageSet: false,
spec: volume.NewSpecFromPersistentVolume(makeTestPV(pvName, 10, testDriver, "test-vol1"), false),
},
{
testName: "failure with volume source",
volName: "test-vol1",
devicePath: "path1",
deviceMountPath: "path2",
shouldFail: true,
spec: volume.NewSpecFromVolume(makeTestVol(pvName, testDriver)),
},
}
for _, tc := range testCases {
t.Logf("Running test case: %s", tc.testName)
var spec *volume.Spec
pvName := "test-pv"
// Setup
// Create a new attacher
@ -777,11 +1087,6 @@ func TestAttacherMountDevice(t *testing.T) {
}
nodeName := string(csiAttacher.plugin.host.GetNodeName())
// Create spec
pv := makeTestPV(pvName, 10, testDriver, tc.volName)
spec = volume.NewSpecFromPersistentVolume(pv, pv.Spec.PersistentVolumeSource.CSI.ReadOnly)
attachID := getAttachmentName(tc.volName, testDriver, nodeName)
// Set up volume attachment
@ -795,7 +1100,147 @@ func TestAttacherMountDevice(t *testing.T) {
}()
// Run
err = csiAttacher.MountDevice(spec, tc.devicePath, tc.deviceMountPath)
err = csiAttacher.MountDevice(tc.spec, tc.devicePath, tc.deviceMountPath)
// Verify
if err != nil {
if !tc.shouldFail {
t.Errorf("test should not fail, but error occurred: %v", err)
}
continue
}
if err == nil && tc.shouldFail {
t.Errorf("test should fail, but no error occurred")
}
// Verify call goes through all the way
numStaged := 1
if !tc.stageUnstageSet {
numStaged = 0
}
cdc := csiAttacher.csiClient.(*fakeCsiDriverClient)
staged := cdc.nodeClient.GetNodeStagedVolumes()
if len(staged) != numStaged {
t.Errorf("got wrong number of staged volumes, expecting %v got: %v", numStaged, len(staged))
}
if tc.stageUnstageSet {
vol, ok := staged[tc.volName]
if !ok {
t.Errorf("could not find staged volume: %s", tc.volName)
}
if vol.Path != tc.deviceMountPath {
t.Errorf("expected mount path: %s. got: %s", tc.deviceMountPath, vol.Path)
}
}
}
}
func TestAttacherMountDeviceWithInline(t *testing.T) {
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIInlineVolume, true)()
pvName := "test-pv"
testCases := []struct {
testName string
volName string
devicePath string
deviceMountPath string
stageUnstageSet bool
shouldFail bool
spec *volume.Spec
}{
{
testName: "normal PV",
volName: "test-vol1",
devicePath: "path1",
deviceMountPath: "path2",
stageUnstageSet: true,
spec: volume.NewSpecFromPersistentVolume(makeTestPV(pvName, 10, testDriver, "test-vol1"), false),
},
{
testName: "failure with volSrc",
volName: "test-vol1",
devicePath: "path1",
deviceMountPath: "path2",
shouldFail: true,
spec: volume.NewSpecFromVolume(makeTestVol(pvName, testDriver)),
},
{
testName: "no vol name",
volName: "",
devicePath: "path1",
deviceMountPath: "path2",
stageUnstageSet: true,
shouldFail: true,
spec: volume.NewSpecFromPersistentVolume(makeTestPV(pvName, 10, testDriver, ""), false),
},
{
testName: "no device path",
volName: "test-vol1",
devicePath: "",
deviceMountPath: "path2",
stageUnstageSet: true,
shouldFail: false,
spec: volume.NewSpecFromPersistentVolume(makeTestPV(pvName, 10, testDriver, "test-vol1"), false),
},
{
testName: "no device mount path",
volName: "test-vol1",
devicePath: "path1",
deviceMountPath: "",
stageUnstageSet: true,
shouldFail: true,
spec: volume.NewSpecFromPersistentVolume(makeTestPV(pvName, 10, testDriver, "test-vol1"), false),
},
{
testName: "stage_unstage cap not set",
volName: "test-vol1",
devicePath: "path1",
deviceMountPath: "path2",
stageUnstageSet: false,
spec: volume.NewSpecFromPersistentVolume(makeTestPV(pvName, 10, testDriver, "test-vol1"), false),
},
{
testName: "missing spec",
volName: "test-vol1",
devicePath: "path1",
deviceMountPath: "path2",
shouldFail: true,
},
}
for _, tc := range testCases {
t.Logf("Running test case: %s", tc.testName)
// Setup
// Create a new attacher
plug, fakeWatcher, tmpDir, _ := newTestWatchPlugin(t, nil)
defer os.RemoveAll(tmpDir)
attacher, err0 := plug.NewAttacher()
if err0 != nil {
t.Fatalf("failed to create new attacher: %v", err0)
}
csiAttacher := attacher.(*csiAttacher)
csiAttacher.csiClient = setupClient(t, tc.stageUnstageSet)
if tc.deviceMountPath != "" {
tc.deviceMountPath = filepath.Join(tmpDir, tc.deviceMountPath)
}
nodeName := string(csiAttacher.plugin.host.GetNodeName())
attachID := getAttachmentName(tc.volName, testDriver, nodeName)
// Set up volume attachment
attachment := makeTestAttachment(attachID, nodeName, pvName)
_, err := csiAttacher.k8s.StorageV1().VolumeAttachments().Create(attachment)
if err != nil {
t.Fatalf("failed to attach: %v", err)
}
go func() {
fakeWatcher.Delete(attachment)
}()
// Run
err = csiAttacher.MountDevice(tc.spec, tc.devicePath, tc.deviceMountPath)
// Verify
if err != nil {

View File

@ -76,12 +76,13 @@ func (c *fakeCsiDriverClient) NodePublishVolume(
) error {
c.t.Log("calling fake.NodePublishVolume...")
req := &csipbv1.NodePublishVolumeRequest{
VolumeId: volID,
TargetPath: targetPath,
Readonly: readOnly,
PublishContext: publishContext,
VolumeContext: volumeContext,
Secrets: secrets,
VolumeId: volID,
TargetPath: targetPath,
StagingTargetPath: stagingTargetPath,
Readonly: readOnly,
PublishContext: publishContext,
VolumeContext: volumeContext,
Secrets: secrets,
VolumeCapability: &csipbv1.VolumeCapability{
AccessMode: &csipbv1.VolumeCapability_AccessMode{
Mode: asCSIAccessModeV1(accessMode),

View File

@ -18,6 +18,7 @@ package csi
import (
"context"
"crypto/sha256"
"errors"
"fmt"
"os"
@ -42,13 +43,15 @@ var (
volHandle,
driverName,
nodeName,
attachmentID string
attachmentID,
driverMode string
}{
"specVolID",
"volumeHandle",
"driverName",
"nodeName",
"attachmentID",
"driverMode",
}
)
@ -57,6 +60,7 @@ type csiMountMgr struct {
k8s kubernetes.Interface
plugin *csiPlugin
driverName csiDriverName
driverMode driverMode
volumeID string
specVolumeID string
readOnly bool
@ -107,49 +111,97 @@ func (c *csiMountMgr) SetUpAt(dir string, fsGroup *int64) error {
return nil
}
csiSource, err := getCSISourceFromSpec(c.spec)
csi := c.csiClient
ctx, cancel := context.WithTimeout(context.Background(), csiTimeout)
defer cancel()
volSrc, pvSrc, err := getSourceFromSpec(c.spec)
if err != nil {
klog.Error(log("mounter.SetupAt failed to get CSI persistent source: %v", err))
return err
}
csi := c.csiClient
ctx, cancel := context.WithTimeout(context.Background(), csiTimeout)
defer cancel()
driverName := c.driverName
volumeHandle := c.volumeID
readOnly := c.readOnly
accessMode := api.ReadWriteOnce
// Check for STAGE_UNSTAGE_VOLUME set and populate deviceMountPath if so
deviceMountPath := ""
stageUnstageSet, err := csi.NodeSupportsStageUnstage(ctx)
if err != nil {
klog.Error(log("mounter.SetUpAt failed to check for STAGE_UNSTAGE_VOLUME capabilty: %v", err))
return err
}
var (
fsType string
volAttribs map[string]string
nodePublishSecrets map[string]string
publishContext map[string]string
mountOptions []string
deviceMountPath string
secretRef *api.SecretReference
)
if stageUnstageSet {
deviceMountPath, err = makeDeviceMountPath(c.plugin, c.spec)
switch {
case volSrc != nil:
if !utilfeature.DefaultFeatureGate.Enabled(features.CSIInlineVolume) {
return fmt.Errorf("CSIInlineVolume feature required")
}
if c.driverMode != ephemeralDriverMode {
return fmt.Errorf("unexpected driver mode: %s", c.driverMode)
}
if volSrc.FSType != nil {
fsType = *volSrc.FSType
}
volAttribs = volSrc.VolumeAttributes
if volSrc.NodePublishSecretRef != nil {
secretName := volSrc.NodePublishSecretRef.Name
ns := c.pod.Namespace
secretRef = &api.SecretReference{Name: secretName, Namespace: ns}
}
case pvSrc != nil:
if c.driverMode != persistentDriverMode {
return fmt.Errorf("unexpected driver mode: %s", c.driverMode)
}
fsType = pvSrc.FSType
volAttribs = pvSrc.VolumeAttributes
if pvSrc.NodePublishSecretRef != nil {
secretRef = pvSrc.NodePublishSecretRef
}
//TODO (vladimirvivien) implement better AccessModes mapping between k8s and CSI
if c.spec.PersistentVolume.Spec.AccessModes != nil {
accessMode = c.spec.PersistentVolume.Spec.AccessModes[0]
}
mountOptions = c.spec.PersistentVolume.Spec.MountOptions
// Check for STAGE_UNSTAGE_VOLUME set and populate deviceMountPath if so
stageUnstageSet, err := csi.NodeSupportsStageUnstage(ctx)
if err != nil {
klog.Error(log("mounter.SetUpAt failed to make device mount path: %v", err))
klog.Error(log("mounter.SetUpAt failed to check for STAGE_UNSTAGE_VOLUME capabilty: %v", err))
return err
}
}
// search for attachment by VolumeAttachment.Spec.Source.PersistentVolumeName
if c.publishContext == nil {
nodeName := string(c.plugin.host.GetNodeName())
c.publishContext, err = c.plugin.getPublishContext(c.k8s, c.volumeID, string(c.driverName), nodeName)
if err != nil {
return err
}
}
attribs := csiSource.VolumeAttributes
nodePublishSecrets := map[string]string{}
if csiSource.NodePublishSecretRef != nil {
nodePublishSecrets, err = getCredentialsFromSecret(c.k8s, csiSource.NodePublishSecretRef)
if err != nil {
return fmt.Errorf("fetching NodePublishSecretRef %s/%s failed: %v",
csiSource.NodePublishSecretRef.Namespace, csiSource.NodePublishSecretRef.Name, err)
if stageUnstageSet {
deviceMountPath, err = makeDeviceMountPath(c.plugin, c.spec)
if err != nil {
klog.Error(log("mounter.SetUpAt failed to make device mount path: %v", err))
return err
}
}
// search for attachment by VolumeAttachment.Spec.Source.PersistentVolumeName
if c.publishContext == nil {
nodeName := string(c.plugin.host.GetNodeName())
c.publishContext, err = c.plugin.getPublishContext(c.k8s, volumeHandle, string(driverName), nodeName)
if err != nil {
return err
}
publishContext = c.publishContext
}
default:
return fmt.Errorf("volume source not found in volume.Spec")
}
// create target_dir before call to NodePublish
@ -159,10 +211,14 @@ func (c *csiMountMgr) SetUpAt(dir string, fsGroup *int64) error {
}
klog.V(4).Info(log("created target path successfully [%s]", dir))
//TODO (vladimirvivien) implement better AccessModes mapping between k8s and CSI
accessMode := api.ReadWriteOnce
if c.spec.PersistentVolume.Spec.AccessModes != nil {
accessMode = c.spec.PersistentVolume.Spec.AccessModes[0]
nodePublishSecrets = map[string]string{}
if secretRef != nil {
nodePublishSecrets, err = getCredentialsFromSecret(c.k8s, secretRef)
if err != nil {
return fmt.Errorf("fetching NodePublishSecretRef %s/%s failed: %v",
secretRef.Namespace, secretRef.Name, err)
}
}
// Inject pod information into volume_attributes
@ -172,28 +228,27 @@ func (c *csiMountMgr) SetUpAt(dir string, fsGroup *int64) error {
return err
}
if podAttrs != nil {
if attribs == nil {
attribs = podAttrs
if volAttribs == nil {
volAttribs = podAttrs
} else {
for k, v := range podAttrs {
attribs[k] = v
volAttribs[k] = v
}
}
}
fsType := csiSource.FSType
err = csi.NodePublishVolume(
ctx,
c.volumeID,
c.readOnly,
volumeHandle,
readOnly,
deviceMountPath,
dir,
accessMode,
c.publishContext,
attribs,
publishContext,
volAttribs,
nodePublishSecrets,
fsType,
c.spec.PersistentVolume.Spec.MountOptions,
mountOptions,
)
if err != nil {
@ -387,3 +442,9 @@ func removeMountDir(plug *csiPlugin, mountPath string) error {
}
return nil
}
// makeVolumeHandle returns csi-<sha256(podUID,volSourceSpecName)>
func makeVolumeHandle(podUID, volSourceSpecName string) string {
result := sha256.Sum256([]byte(fmt.Sprintf("%s%s", podUID, volSourceSpecName)))
return fmt.Sprintf("csi-%x", result)
}

View File

@ -21,6 +21,7 @@ import (
"encoding/json"
"fmt"
"io/ioutil"
"math/rand"
"os"
"path"
"testing"
@ -266,6 +267,266 @@ func TestMounterSetUp(t *testing.T) {
MounterSetUpTests(t, false)
})
}
func TestMounterSetUpSimple(t *testing.T) {
fakeClient := fakeclient.NewSimpleClientset()
plug, tmpDir := newTestPlugin(t, fakeClient)
defer os.RemoveAll(tmpDir)
testCases := []struct {
name string
podUID types.UID
mode driverMode
fsType string
options []string
spec func(string, []string) *volume.Spec
shouldFail bool
}{
{
name: "setup with vol source",
podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())),
mode: ephemeralDriverMode,
fsType: "ext4",
shouldFail: true,
spec: func(fsType string, options []string) *volume.Spec {
volSrc := makeTestVol("pv1", testDriver)
volSrc.CSI.FSType = &fsType
return volume.NewSpecFromVolume(volSrc)
},
},
{
name: "setup with persistent source",
podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())),
mode: persistentDriverMode,
fsType: "zfs",
spec: func(fsType string, options []string) *volume.Spec {
pvSrc := makeTestPV("pv1", 20, testDriver, "vol1")
pvSrc.Spec.CSI.FSType = fsType
pvSrc.Spec.MountOptions = options
return volume.NewSpecFromPersistentVolume(pvSrc, false)
},
},
{
name: "setup with persistent source without unspecified fstype and options",
podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())),
mode: persistentDriverMode,
spec: func(fsType string, options []string) *volume.Spec {
return volume.NewSpecFromPersistentVolume(makeTestPV("pv1", 20, testDriver, "vol2"), false)
},
},
{
name: "setup with missing spec",
shouldFail: true,
spec: func(fsType string, options []string) *volume.Spec { return nil },
},
}
for _, tc := range testCases {
registerFakePlugin(testDriver, "endpoint", []string{"1.0.0"}, t)
t.Run(tc.name, func(t *testing.T) {
mounter, err := plug.NewMounter(
tc.spec(tc.fsType, tc.options),
&api.Pod{ObjectMeta: meta.ObjectMeta{UID: tc.podUID, Namespace: testns}},
volume.VolumeOptions{},
)
if tc.shouldFail && err != nil {
t.Log(err)
return
}
if !tc.shouldFail && err != nil {
t.Fatal("unexpected error:", err)
}
if mounter == nil {
t.Fatal("failed to create CSI mounter")
}
csiMounter := mounter.(*csiMountMgr)
csiMounter.csiClient = setupClient(t, true)
if csiMounter.driverMode != persistentDriverMode {
t.Fatal("unexpected driver mode: ", csiMounter.driverMode)
}
attachID := getAttachmentName(csiMounter.volumeID, string(csiMounter.driverName), string(plug.host.GetNodeName()))
attachment := makeTestAttachment(attachID, "test-node", csiMounter.spec.Name())
_, err = csiMounter.k8s.StorageV1().VolumeAttachments().Create(attachment)
if err != nil {
t.Fatalf("failed to setup VolumeAttachment: %v", err)
}
// Mounter.SetUp()
if err := csiMounter.SetUp(nil); err != nil {
t.Fatalf("mounter.Setup failed: %v", err)
}
// ensure call went all the way
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.VolumeHandle != csiMounter.volumeID {
t.Error("volumeHandle not sent to CSI driver properly")
}
devicePath, err := makeDeviceMountPath(plug, csiMounter.spec)
if err != nil {
t.Fatal(err)
}
if vol.DeviceMountPath != devicePath {
t.Errorf("DeviceMountPath not sent properly to CSI driver: %s, %s", vol.DeviceMountPath, devicePath)
}
if !reflect.DeepEqual(vol.MountFlags, csiMounter.spec.PersistentVolume.Spec.MountOptions) {
t.Errorf("unexpected mount flags passed to driver: %+v", vol.MountFlags)
}
if vol.FSType != tc.fsType {
t.Error("unexpected FSType sent to driver:", vol.FSType)
}
if vol.Path != csiMounter.GetPath() {
t.Error("csi server may not have received NodePublishVolume call")
}
})
}
}
func TestMounterSetUpWithInline(t *testing.T) {
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIInlineVolume, true)()
fakeClient := fakeclient.NewSimpleClientset()
plug, tmpDir := newTestPlugin(t, fakeClient)
defer os.RemoveAll(tmpDir)
testCases := []struct {
name string
podUID types.UID
mode driverMode
fsType string
options []string
spec func(string, []string) *volume.Spec
shouldFail bool
}{
{
name: "setup with vol source",
podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())),
mode: ephemeralDriverMode,
fsType: "ext4",
spec: func(fsType string, options []string) *volume.Spec {
volSrc := makeTestVol("pv1", testDriver)
volSrc.CSI.FSType = &fsType
return volume.NewSpecFromVolume(volSrc)
},
},
{
name: "setup with persistent source",
podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())),
mode: persistentDriverMode,
fsType: "zfs",
spec: func(fsType string, options []string) *volume.Spec {
pvSrc := makeTestPV("pv1", 20, testDriver, "vol1")
pvSrc.Spec.CSI.FSType = fsType
pvSrc.Spec.MountOptions = options
return volume.NewSpecFromPersistentVolume(pvSrc, false)
},
},
{
name: "setup with persistent source without unspecified fstype and options",
podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())),
mode: persistentDriverMode,
spec: func(fsType string, options []string) *volume.Spec {
return volume.NewSpecFromPersistentVolume(makeTestPV("pv1", 20, testDriver, "vol2"), false)
},
},
{
name: "setup with missing spec",
shouldFail: true,
spec: func(fsType string, options []string) *volume.Spec { return nil },
},
}
for _, tc := range testCases {
registerFakePlugin(testDriver, "endpoint", []string{"1.0.0"}, t)
t.Run(tc.name, func(t *testing.T) {
mounter, err := plug.NewMounter(
tc.spec(tc.fsType, tc.options),
&api.Pod{ObjectMeta: meta.ObjectMeta{UID: tc.podUID, Namespace: testns}},
volume.VolumeOptions{},
)
if tc.shouldFail && err != nil {
t.Log(err)
return
}
if !tc.shouldFail && err != nil {
t.Fatal("unexpected error:", err)
}
if mounter == nil {
t.Fatal("failed to create CSI mounter")
}
csiMounter := mounter.(*csiMountMgr)
csiMounter.csiClient = setupClient(t, true)
if csiMounter.driverMode != tc.mode {
t.Fatal("unexpected driver mode: ", csiMounter.driverMode)
}
if csiMounter.driverMode == ephemeralDriverMode && csiMounter.volumeID != makeVolumeHandle(string(tc.podUID), csiMounter.specVolumeID) {
t.Fatal("unexpected generated volumeHandle:", csiMounter.volumeID)
}
if csiMounter.driverMode == persistentDriverMode {
attachID := getAttachmentName(csiMounter.volumeID, string(csiMounter.driverName), string(plug.host.GetNodeName()))
attachment := makeTestAttachment(attachID, "test-node", csiMounter.spec.Name())
_, err = csiMounter.k8s.StorageV1().VolumeAttachments().Create(attachment)
if err != nil {
t.Fatalf("failed to setup VolumeAttachment: %v", err)
}
}
// Mounter.SetUp()
if err := csiMounter.SetUp(nil); err != nil {
t.Fatalf("mounter.Setup failed: %v", err)
}
// ensure call went all the way
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.VolumeHandle != csiMounter.volumeID {
t.Error("volumeHandle not sent to CSI driver properly")
}
// validate stagingTargetPath
if tc.mode == ephemeralDriverMode && vol.DeviceMountPath != "" {
t.Errorf("unexpected devicePathTarget sent to driver: %s", vol.DeviceMountPath)
}
if tc.mode == persistentDriverMode {
devicePath, err := makeDeviceMountPath(plug, csiMounter.spec)
if err != nil {
t.Fatal(err)
}
if vol.DeviceMountPath != devicePath {
t.Errorf("DeviceMountPath not sent properly to CSI driver: %s, %s", vol.DeviceMountPath, devicePath)
}
if !reflect.DeepEqual(vol.MountFlags, csiMounter.spec.PersistentVolume.Spec.MountOptions) {
t.Errorf("unexpected mount flags passed to driver: %+v", vol.MountFlags)
}
}
if vol.FSType != tc.fsType {
t.Error("unexpected FSType sent to driver:", vol.FSType)
}
if vol.Path != csiMounter.GetPath() {
t.Error("csi server may not have received NodePublishVolume call")
}
})
}
}
func TestMounterSetUpWithFSGroup(t *testing.T) {
fakeClient := fakeclient.NewSimpleClientset()
plug, tmpDir := newTestPlugin(t, fakeClient)

View File

@ -74,6 +74,12 @@ type csiPlugin struct {
csiDriverInformer csiinformer.CSIDriverInformer
}
//TODO (vladimirvivien) add this type to storage api
type driverMode string
const persistentDriverMode driverMode = "persistent"
const ephemeralDriverMode driverMode = "ephemeral"
// ProbeVolumePlugins returns implemented plugins
func ProbeVolumePlugins() []volume.VolumePlugin {
p := &csiPlugin{
@ -303,7 +309,7 @@ func (p *csiPlugin) GetPluginName() string {
// GetvolumeName returns a concatenated string of CSIVolumeSource.Driver<volNameSe>CSIVolumeSource.VolumeHandle
// That string value is used in Detach() to extract driver name and volumeName.
func (p *csiPlugin) GetVolumeName(spec *volume.Spec) (string, error) {
csi, err := getCSISourceFromSpec(spec)
csi, err := getPVSourceFromSpec(spec)
if err != nil {
klog.Error(log("plugin.GetVolumeName failed to extract volume source from spec: %v", err))
return "", err
@ -316,6 +322,14 @@ func (p *csiPlugin) GetVolumeName(spec *volume.Spec) (string, error) {
func (p *csiPlugin) CanSupport(spec *volume.Spec) bool {
// TODO (vladimirvivien) CanSupport should also take into account
// the availability/registration of specified Driver in the volume source
if spec == nil {
return false
}
if utilfeature.DefaultFeatureGate.Enabled(features.CSIInlineVolume) {
return (spec.PersistentVolume != nil && spec.PersistentVolume.Spec.CSI != nil) ||
(spec.Volume != nil && spec.Volume.CSI != nil)
}
return spec.PersistentVolume != nil && spec.PersistentVolume.Spec.CSI != nil
}
@ -331,11 +345,34 @@ func (p *csiPlugin) NewMounter(
spec *volume.Spec,
pod *api.Pod,
_ volume.VolumeOptions) (volume.Mounter, error) {
pvSource, err := getCSISourceFromSpec(spec)
volSrc, pvSrc, err := getSourceFromSpec(spec)
if err != nil {
return nil, err
}
readOnly, err := getReadOnlyFromSpec(spec)
var (
driverName string
volumeHandle string
readOnly bool
)
switch {
case volSrc != nil && utilfeature.DefaultFeatureGate.Enabled(features.CSIInlineVolume):
volumeHandle = makeVolumeHandle(string(pod.UID), spec.Name())
driverName = volSrc.Driver
if volSrc.ReadOnly != nil {
readOnly = *volSrc.ReadOnly
}
case pvSrc != nil:
driverName = pvSrc.Driver
volumeHandle = pvSrc.VolumeHandle
readOnly = spec.ReadOnly
default:
return nil, fmt.Errorf("volume source not found in volume.Spec")
}
driverMode, err := p.getDriverMode(spec)
if err != nil {
return nil, err
}
@ -346,7 +383,7 @@ func (p *csiPlugin) NewMounter(
return nil, errors.New("failed to get a Kubernetes client")
}
csi, err := newCsiDriverClient(csiDriverName(pvSource.Driver))
csi, err := newCsiDriverClient(csiDriverName(driverName))
if err != nil {
return nil, err
}
@ -357,8 +394,9 @@ func (p *csiPlugin) NewMounter(
spec: spec,
pod: pod,
podUID: pod.UID,
driverName: csiDriverName(pvSource.Driver),
volumeID: pvSource.VolumeHandle,
driverName: csiDriverName(driverName),
driverMode: driverMode,
volumeID: volumeHandle,
specVolumeID: spec.Name(),
csiClient: csi,
readOnly: readOnly,
@ -376,15 +414,17 @@ func (p *csiPlugin) NewMounter(
// persist volume info data for teardown
node := string(p.host.GetNodeName())
attachID := getAttachmentName(pvSource.VolumeHandle, pvSource.Driver, node)
volData := map[string]string{
volDataKey.specVolID: spec.Name(),
volDataKey.volHandle: pvSource.VolumeHandle,
volDataKey.driverName: pvSource.Driver,
volDataKey.nodeName: node,
volDataKey.attachmentID: attachID,
volDataKey.specVolID: spec.Name(),
volDataKey.volHandle: volumeHandle,
volDataKey.driverName: driverName,
volDataKey.nodeName: node,
volDataKey.driverMode: string(driverMode),
}
attachID := getAttachmentName(volumeHandle, driverName, node)
volData[volDataKey.attachmentID] = attachID
if err := saveVolumeData(dataDir, volDataFileName, volData); err != nil {
klog.Error(log("failed to save volume info data: %v", err))
if err := os.RemoveAll(dataDir); err != nil {
@ -437,23 +477,58 @@ func (p *csiPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.S
klog.V(4).Info(log("plugin.ConstructVolumeSpec extracted [%#v]", volData))
var spec *volume.Spec
inlineEnabled := utilfeature.DefaultFeatureGate.Enabled(features.CSIInlineVolume)
if inlineEnabled {
mode := driverMode(volData[volDataKey.driverMode])
switch {
case mode == ephemeralDriverMode:
spec = p.constructVolSourceSpec(volData[volDataKey.specVolID], volData[volDataKey.driverName])
case mode == persistentDriverMode:
fallthrough
default:
spec = p.constructPVSourceSpec(volData[volDataKey.specVolID], volData[volDataKey.driverName], volData[volDataKey.volHandle])
}
} else {
spec = p.constructPVSourceSpec(volData[volDataKey.specVolID], volData[volDataKey.driverName], volData[volDataKey.volHandle])
}
return spec, nil
}
// constructVolSourceSpec constructs volume.Spec with CSIVolumeSource
func (p *csiPlugin) constructVolSourceSpec(volSpecName, driverName string) *volume.Spec {
vol := &api.Volume{
Name: volSpecName,
VolumeSource: api.VolumeSource{
CSI: &api.CSIVolumeSource{
Driver: driverName,
},
},
}
return volume.NewSpecFromVolume(vol)
}
//constructPVSourceSpec constructs volume.Spec with CSIPersistentVolumeSource
func (p *csiPlugin) constructPVSourceSpec(volSpecName, driverName, volumeHandle string) *volume.Spec {
fsMode := api.PersistentVolumeFilesystem
pv := &api.PersistentVolume{
ObjectMeta: meta.ObjectMeta{
Name: volData[volDataKey.specVolID],
Name: volSpecName,
},
Spec: api.PersistentVolumeSpec{
PersistentVolumeSource: api.PersistentVolumeSource{
CSI: &api.CSIPersistentVolumeSource{
Driver: volData[volDataKey.driverName],
VolumeHandle: volData[volDataKey.volHandle],
Driver: driverName,
VolumeHandle: volumeHandle,
},
},
VolumeMode: &fsMode,
},
}
return volume.NewSpecFromPersistentVolume(pv, false), nil
return volume.NewSpecFromPersistentVolume(pv, false)
}
func (p *csiPlugin) SupportsMountOption() bool {
@ -506,24 +581,31 @@ func (p *csiPlugin) NewDetacher() (volume.Detacher, error) {
}, nil
}
// TODO change CanAttach to return error to propagate ability
// to support Attachment or an error - see https://github.com/kubernetes/kubernetes/issues/74810
func (p *csiPlugin) CanAttach(spec *volume.Spec) bool {
if spec.PersistentVolume == nil {
klog.Error(log("plugin.CanAttach test failed, spec missing PersistentVolume"))
driverMode, err := p.getDriverMode(spec)
if err != nil {
return false
}
var driverName string
if spec.PersistentVolume.Spec.CSI != nil {
driverName = spec.PersistentVolume.Spec.CSI.Driver
} else {
klog.Error(log("plugin.CanAttach test failed, spec missing CSIPersistentVolume"))
if driverMode == ephemeralDriverMode {
klog.V(4).Info(log("driver ephemeral mode detected for spec %v", spec.Name))
return false
}
pvSrc, err := getCSISourceFromSpec(spec)
if err != nil {
klog.Error(log("plugin.CanAttach failed to get info from spec: %s", err))
return false
}
driverName := pvSrc.Driver
skipAttach, err := p.skipAttach(driverName)
if err != nil {
klog.Error(log("plugin.CanAttach error when calling plugin.skipAttach for driver %s: %s", driverName, err))
return false
}
return !skipAttach
@ -675,6 +757,8 @@ func (p *csiPlugin) ConstructBlockVolumeSpec(podUID types.UID, specVolName, mapP
return volume.NewSpecFromPersistentVolume(pv, false), nil
}
// skipAttach looks up CSIDriver object associated with driver name
// to determine if driver requies attachment volume operation
func (p *csiPlugin) skipAttach(driver string) (bool, error) {
if !utilfeature.DefaultFeatureGate.Enabled(features.CSIDriverRegistry) {
return false, nil
@ -696,6 +780,26 @@ func (p *csiPlugin) skipAttach(driver string) (bool, error) {
return false, nil
}
// getDriverMode returns the driver mode for the specified spec: {persistent|ephemeral}.
// 1) If mode cannot be determined, it will default to "persistent".
// 2) If Mode cannot be resolved to either {persistent | ephemeral}, an error is returned
// See https://github.com/kubernetes/enhancements/blob/master/keps/sig-storage/20190122-csi-inline-volumes.md
func (p *csiPlugin) getDriverMode(spec *volume.Spec) (driverMode, error) {
// TODO (vladimirvivien) ultimately, mode will be retrieved from CSIDriver.Spec.Mode.
// However, in alpha version, mode is determined by the volume source:
// 1) if volume.Spec.Volume.CSI != nil -> mode is ephemeral
// 2) if volume.Spec.PersistentVolume.Spec.CSI != nil -> persistent
volSrc, _, err := getSourceFromSpec(spec)
if err != nil {
return "", err
}
if volSrc != nil && utilfeature.DefaultFeatureGate.Enabled(features.CSIInlineVolume) {
return ephemeralDriverMode, nil
}
return persistentDriverMode, nil
}
func (p *csiPlugin) getPublishContext(client clientset.Interface, handle, driver, nodeName string) (map[string]string, error) {
skip, err := p.skipAttach(driver)
if err != nil {

View File

@ -18,6 +18,7 @@ package csi
import (
"fmt"
"math/rand"
"os"
"path"
"path/filepath"
@ -99,6 +100,19 @@ func makeTestPV(name string, sizeGig int, driverName, volID string) *api.Persist
}
}
func makeTestVol(name string, driverName string) *api.Volume {
ro := false
return &api.Volume{
Name: name,
VolumeSource: api.VolumeSource{
CSI: &api.CSIVolumeSource{
Driver: driverName,
ReadOnly: &ro,
},
},
}
}
func registerFakePlugin(pluginName, endpoint string, versions []string, t *testing.T) {
highestSupportedVersions, err := highestSupportedVersion(versions)
if err != nil {
@ -131,22 +145,105 @@ func TestPluginGetVolumeName(t *testing.T) {
name string
driverName string
volName string
spec *volume.Spec
shouldFail bool
}{
{"alphanum names", "testdr", "testvol", false},
{"mixchar driver", "test.dr.cc", "testvol", false},
{"mixchar volume", "testdr", "test-vol-name", false},
{"mixchars all", "test-driver", "test.vol.name", false},
{
name: "alphanum names",
driverName: "testdr",
volName: "testvol",
spec: volume.NewSpecFromPersistentVolume(makeTestPV("test-pv", 10, "testdr", "testvol"), false),
},
{
name: "mixchar driver",
driverName: "test.dr.cc",
volName: "testvol",
spec: volume.NewSpecFromPersistentVolume(makeTestPV("test-pv", 10, "test.dr.cc", "testvol"), false),
},
{
name: "mixchar volume",
driverName: "testdr",
volName: "test-vol-name",
spec: volume.NewSpecFromPersistentVolume(makeTestPV("test-pv", 10, "testdr", "test-vol-name"), false),
},
{
name: "mixchars all",
driverName: "test-driver",
volName: "test.vol.name",
spec: volume.NewSpecFromPersistentVolume(makeTestPV("test-pv", 10, "test-driver", "test.vol.name"), false),
},
{
name: "volume source with mixchars all",
driverName: "test-driver",
volName: "test.vol.name",
spec: volume.NewSpecFromVolume(makeTestVol("test-pv", "test-driver")),
shouldFail: true, // csi inline feature off
},
{
name: "missing spec",
shouldFail: true,
},
}
for _, tc := range testCases {
t.Logf("testing: %s", tc.name)
registerFakePlugin(tc.driverName, "endpoint", []string{"0.3.0"}, t)
pv := makeTestPV("test-pv", 10, tc.driverName, tc.volName)
spec := volume.NewSpecFromPersistentVolume(pv, false)
name, err := plug.GetVolumeName(spec)
if tc.shouldFail && err == nil {
t.Fatal("GetVolumeName should fail, but got err=nil")
name, err := plug.GetVolumeName(tc.spec)
if tc.shouldFail != (err != nil) {
t.Fatal("shouldFail does match expected error")
}
if tc.shouldFail && err != nil {
t.Log(err)
continue
}
if name != fmt.Sprintf("%s%s%s", tc.driverName, volNameSep, tc.volName) {
t.Errorf("unexpected volume name %s", name)
}
}
}
func TestPluginGetVolumeNameWithInline(t *testing.T) {
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIInlineVolume, true)()
plug, tmpDir := newTestPlugin(t, nil)
defer os.RemoveAll(tmpDir)
testCases := []struct {
name string
driverName string
volName string
shouldFail bool
spec *volume.Spec
}{
{
name: "missing spec",
shouldFail: true,
},
{
name: "alphanum names for pv",
driverName: "testdr",
volName: "testvol",
spec: volume.NewSpecFromPersistentVolume(makeTestPV("test-pv", 10, "testdr", "testvol"), false),
},
{
name: "alphanum names for vol source",
driverName: "testdr",
volName: "testvol",
spec: volume.NewSpecFromVolume(makeTestVol("test-pv", "testdr")),
shouldFail: true,
},
}
for _, tc := range testCases {
t.Logf("testing: %s", tc.name)
registerFakePlugin(tc.driverName, "endpoint", []string{"0.3.0"}, t)
name, err := plug.GetVolumeName(tc.spec)
if tc.shouldFail != (err != nil) {
t.Fatal("shouldFail does match expected error")
}
if tc.shouldFail && err != nil {
t.Log(err)
continue
}
if name != fmt.Sprintf("%s%s%s", tc.driverName, volNameSep, tc.volName) {
t.Errorf("unexpected volume name %s", name)
@ -157,15 +254,79 @@ func TestPluginGetVolumeName(t *testing.T) {
func TestPluginCanSupport(t *testing.T) {
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()
tests := []struct {
name string
spec *volume.Spec
canSupport bool
}{
{
name: "no spec provided",
canSupport: false,
},
{
name: "can support volume source",
spec: volume.NewSpecFromVolume(makeTestVol("test-vol", testDriver)),
canSupport: false, // csi inline not enabled
},
{
name: "can support persistent volume source",
spec: volume.NewSpecFromPersistentVolume(makeTestPV("test-pv", 20, testDriver, testVol), true),
canSupport: true,
},
}
plug, tmpDir := newTestPlugin(t, nil)
defer os.RemoveAll(tmpDir)
registerFakePlugin(testDriver, "endpoint", []string{"1.0.0"}, t)
pv := makeTestPV("test-pv", 10, testDriver, testVol)
spec := volume.NewSpecFromPersistentVolume(pv, false)
if !plug.CanSupport(spec) {
t.Errorf("should support CSI spec")
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
actual := plug.CanSupport(tc.spec)
if tc.canSupport != actual {
t.Errorf("expecting canSupport %t, got %t", tc.canSupport, actual)
}
})
}
}
func TestPluginCanSupportWithInline(t *testing.T) {
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIInlineVolume, true)()
tests := []struct {
name string
spec *volume.Spec
canSupport bool
}{
{
name: "no spec provided",
canSupport: false,
},
{
name: "can support volume source",
spec: volume.NewSpecFromVolume(makeTestVol("test-vol", testDriver)),
canSupport: true,
},
{
name: "can support persistent volume source",
spec: volume.NewSpecFromPersistentVolume(makeTestPV("test-pv", 20, testDriver, testVol), true),
canSupport: true,
},
}
plug, tmpDir := newTestPlugin(t, nil)
defer os.RemoveAll(tmpDir)
registerFakePlugin(testDriver, "endpoint", []string{"1.0.0"}, t)
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
actual := plug.CanSupport(tc.spec)
if tc.canSupport != actual {
t.Errorf("expecting canSupport %t, got %t", tc.canSupport, actual)
}
})
}
}
@ -177,108 +338,437 @@ func TestPluginConstructVolumeSpec(t *testing.T) {
testCases := []struct {
name string
originSpec *volume.Spec
specVolID string
data map[string]string
volHandle string
podUID types.UID
shouldFail bool
}{
{
name: "valid spec name",
specVolID: "test.vol.id",
data: map[string]string{volDataKey.specVolID: "test.vol.id", volDataKey.volHandle: "test-vol0", volDataKey.driverName: "test-driver0"},
name: "construct spec1 from original persistent spec",
specVolID: "test.vol.id",
volHandle: "testvol-handle1",
originSpec: volume.NewSpecFromPersistentVolume(makeTestPV("test.vol.id", 20, testDriver, "testvol-handle1"), true),
podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())),
},
{
name: "construct spec2 from original persistent spec",
specVolID: "spec2",
volHandle: "handle2",
originSpec: volume.NewSpecFromPersistentVolume(makeTestPV("spec2", 20, testDriver, "handle2"), true),
podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())),
},
{
name: "construct spec from original volume spec",
specVolID: "volspec",
originSpec: volume.NewSpecFromVolume(makeTestVol("spec2", testDriver)),
podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())),
shouldFail: true, // csi inline off
},
}
for _, tc := range testCases {
t.Logf("test case: %s", tc.name)
dir := getTargetPath(testPodUID, tc.specVolID, plug.host)
registerFakePlugin(testDriver, "endpoint", []string{"1.0.0"}, t)
// create the data file
if tc.data != nil {
mountDir := path.Join(getTargetPath(testPodUID, tc.specVolID, plug.host), "/mount")
if err := os.MkdirAll(mountDir, 0755); err != nil && !os.IsNotExist(err) {
t.Errorf("failed to create dir [%s]: %v", mountDir, err)
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
mounter, err := plug.NewMounter(
tc.originSpec,
&api.Pod{ObjectMeta: meta.ObjectMeta{UID: tc.podUID, Namespace: testns}},
volume.VolumeOptions{},
)
if tc.shouldFail && err != nil {
t.Log(err)
return
}
if err := saveVolumeData(path.Dir(mountDir), volDataFileName, tc.data); err != nil {
if !tc.shouldFail && err != nil {
t.Fatal(err)
}
}
// rebuild spec
spec, err := plug.ConstructVolumeSpec("test-pv", dir)
if tc.shouldFail {
if err == nil {
t.Fatal("expecting ConstructVolumeSpec to fail, but got nil error")
if mounter == nil {
t.Fatal("failed to create CSI mounter")
}
continue
}
csiMounter := mounter.(*csiMountMgr)
volHandle := spec.PersistentVolume.Spec.CSI.VolumeHandle
if volHandle != tc.data[volDataKey.volHandle] {
t.Errorf("expected volID %s, got volID %s", tc.data[volDataKey.volHandle], volHandle)
}
// rebuild spec
spec, err := plug.ConstructVolumeSpec("test-pv", path.Dir(csiMounter.GetPath()))
if err != nil {
t.Fatal(err)
}
if spec == nil {
t.Fatal("nil volume.Spec contstructed")
}
if spec.PersistentVolume.Spec.VolumeMode == nil {
t.Fatalf("Volume mode has not been set.")
}
// inspect spec
if spec.PersistentVolume == nil || spec.PersistentVolume.Spec.CSI == nil {
t.Fatal("CSIPersistentVolume not found in constructed spec ")
}
if *spec.PersistentVolume.Spec.VolumeMode != api.PersistentVolumeFilesystem {
t.Errorf("Unexpected volume mode %q", *spec.PersistentVolume.Spec.VolumeMode)
}
volHandle := spec.PersistentVolume.Spec.CSI.VolumeHandle
if volHandle != tc.originSpec.PersistentVolume.Spec.CSI.VolumeHandle {
t.Error("unexpected volumeHandle constructed:", volHandle)
}
driverName := spec.PersistentVolume.Spec.CSI.Driver
if driverName != tc.originSpec.PersistentVolume.Spec.CSI.Driver {
t.Error("unexpected driverName constructed:", driverName)
}
if spec.Name() != tc.specVolID {
t.Errorf("Unexpected spec name %s", spec.Name())
}
if spec.PersistentVolume.Spec.VolumeMode == nil {
t.Fatalf("Volume mode has not been set.")
}
if *spec.PersistentVolume.Spec.VolumeMode != api.PersistentVolumeFilesystem {
t.Errorf("Unexpected volume mode %q", *spec.PersistentVolume.Spec.VolumeMode)
}
if spec.Name() != tc.specVolID {
t.Errorf("Unexpected spec name constructed %s", spec.Name())
}
})
}
}
func TestPluginConstructVolumeSpecWithInline(t *testing.T) {
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIInlineVolume, true)()
plug, tmpDir := newTestPlugin(t, nil)
defer os.RemoveAll(tmpDir)
testCases := []struct {
name string
originSpec *volume.Spec
specVolID string
volHandle string
podUID types.UID
shouldFail bool
}{
{
name: "construct spec1 from persistent spec",
specVolID: "test.vol.id",
volHandle: "testvol-handle1",
originSpec: volume.NewSpecFromPersistentVolume(makeTestPV("test.vol.id", 20, testDriver, "testvol-handle1"), true),
podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())),
},
{
name: "construct spec2 from persistent spec",
specVolID: "spec2",
volHandle: "handle2",
originSpec: volume.NewSpecFromPersistentVolume(makeTestPV("spec2", 20, testDriver, "handle2"), true),
podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())),
},
{
name: "construct spec from volume spec",
specVolID: "volspec",
originSpec: volume.NewSpecFromVolume(makeTestVol("volspec", testDriver)),
podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())),
},
{
name: "construct spec from volume spec2",
specVolID: "volspec2",
originSpec: volume.NewSpecFromVolume(makeTestVol("volspec2", testDriver)),
podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())),
},
{
name: "missing spec",
podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())),
shouldFail: true,
},
}
registerFakePlugin(testDriver, "endpoint", []string{"1.0.0"}, t)
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
mounter, err := plug.NewMounter(
tc.originSpec,
&api.Pod{ObjectMeta: meta.ObjectMeta{UID: tc.podUID, Namespace: testns}},
volume.VolumeOptions{},
)
if tc.shouldFail && err != nil {
t.Log(err)
return
}
if !tc.shouldFail && err != nil {
t.Fatal(err)
}
if mounter == nil {
t.Fatal("failed to create CSI mounter")
}
csiMounter := mounter.(*csiMountMgr)
// rebuild spec
spec, err := plug.ConstructVolumeSpec("test-pv", path.Dir(csiMounter.GetPath()))
if err != nil {
t.Fatal(err)
}
if spec == nil {
t.Fatal("nil volume.Spec contstructed")
}
if spec.Name() != tc.specVolID {
t.Errorf("unexpected spec name constructed volume.Spec: %s", spec.Name())
}
switch {
case spec.Volume != nil:
if spec.Volume.CSI == nil {
t.Error("missing CSIVolumeSource in constructed volume.Spec")
}
if spec.Volume.CSI.Driver != tc.originSpec.Volume.CSI.Driver {
t.Error("unexpected driver in constructed volume source:", spec.Volume.CSI.Driver)
}
case spec.PersistentVolume != nil:
if spec.PersistentVolume.Spec.CSI == nil {
t.Fatal("missing CSIPersistentVolumeSource in constructed volume.spec")
}
volHandle := spec.PersistentVolume.Spec.CSI.VolumeHandle
if volHandle != tc.originSpec.PersistentVolume.Spec.CSI.VolumeHandle {
t.Error("unexpected volumeHandle constructed in persistent volume source:", volHandle)
}
driverName := spec.PersistentVolume.Spec.CSI.Driver
if driverName != tc.originSpec.PersistentVolume.Spec.CSI.Driver {
t.Error("unexpected driverName constructed in persistent volume source:", driverName)
}
if spec.PersistentVolume.Spec.VolumeMode == nil {
t.Fatalf("Volume mode has not been set.")
}
if *spec.PersistentVolume.Spec.VolumeMode != api.PersistentVolumeFilesystem {
t.Errorf("Unexpected volume mode %q", *spec.PersistentVolume.Spec.VolumeMode)
}
default:
t.Fatal("invalid volume.Spec constructed")
}
})
}
}
func TestPluginNewMounter(t *testing.T) {
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()
plug, tmpDir := newTestPlugin(t, nil)
defer os.RemoveAll(tmpDir)
registerFakePlugin(testDriver, "endpoint", []string{"1.2.0"}, t)
pv := makeTestPV("test-pv", 10, testDriver, testVol)
mounter, err := plug.NewMounter(
volume.NewSpecFromPersistentVolume(pv, pv.Spec.PersistentVolumeSource.CSI.ReadOnly),
&api.Pod{ObjectMeta: meta.ObjectMeta{UID: testPodUID, Namespace: testns}},
volume.VolumeOptions{},
)
if err != nil {
t.Fatalf("Failed to make a new Mounter: %v", err)
tests := []struct {
name string
spec *volume.Spec
podUID types.UID
namespace string
driverMode driverMode
shouldFail bool
}{
{
name: "mounter from persistent volume source",
spec: volume.NewSpecFromPersistentVolume(makeTestPV("test-pv1", 20, testDriver, testVol), true),
podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())),
namespace: "test-ns1",
driverMode: persistentDriverMode,
},
{
name: "mounter from volume source",
spec: volume.NewSpecFromVolume(makeTestVol("test-vol1", testDriver)),
podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())),
namespace: "test-ns2",
driverMode: ephemeralDriverMode,
shouldFail: true, // csi inline not enabled
},
{
name: "mounter from no spec provided",
shouldFail: true,
},
}
if mounter == nil {
t.Fatal("failed to create CSI mounter")
}
csiMounter := mounter.(*csiMountMgr)
for _, test := range tests {
plug, tmpDir := newTestPlugin(t, nil)
defer os.RemoveAll(tmpDir)
// validate mounter fields
if string(csiMounter.driverName) != testDriver {
t.Error("mounter driver name not set")
registerFakePlugin(testDriver, "endpoint", []string{"1.2.0"}, t)
t.Run(test.name, func(t *testing.T) {
mounter, err := plug.NewMounter(
test.spec,
&api.Pod{ObjectMeta: meta.ObjectMeta{UID: test.podUID, Namespace: test.namespace}},
volume.VolumeOptions{},
)
if test.shouldFail != (err != nil) {
t.Fatal("Unexpected error:", err)
}
if test.shouldFail && err != nil {
t.Log(err)
return
}
if mounter == nil {
t.Fatal("failed to create CSI mounter")
}
csiMounter := mounter.(*csiMountMgr)
// validate mounter fields
if string(csiMounter.driverName) != testDriver {
t.Error("mounter driver name not set")
}
if csiMounter.volumeID == "" {
t.Error("mounter volume id not set")
}
if csiMounter.pod == nil {
t.Error("mounter pod not set")
}
if string(csiMounter.podUID) != string(test.podUID) {
t.Error("mounter podUID not set")
}
if csiMounter.csiClient == nil {
t.Error("mounter csiClient is nil")
}
if csiMounter.driverMode != test.driverMode {
t.Error("unexpected driver mode:", csiMounter.driverMode)
}
// ensure data file is created
dataDir := path.Dir(mounter.GetPath())
dataFile := filepath.Join(dataDir, volDataFileName)
if _, err := os.Stat(dataFile); err != nil {
if os.IsNotExist(err) {
t.Errorf("data file not created %s", dataFile)
} else {
t.Fatal(err)
}
}
data, err := loadVolumeData(dataDir, volDataFileName)
if err != nil {
t.Fatal(err)
}
if data[volDataKey.specVolID] != csiMounter.spec.Name() {
t.Error("volume data file unexpected specVolID:", data[volDataKey.specVolID])
}
if data[volDataKey.volHandle] != csiMounter.volumeID {
t.Error("volume data file unexpected volHandle:", data[volDataKey.volHandle])
}
if data[volDataKey.driverName] != string(csiMounter.driverName) {
t.Error("volume data file unexpected driverName:", data[volDataKey.driverName])
}
if data[volDataKey.nodeName] != string(csiMounter.plugin.host.GetNodeName()) {
t.Error("volume data file unexpected nodeName:", data[volDataKey.nodeName])
}
if data[volDataKey.driverMode] != string(test.driverMode) {
t.Error("volume data file unexpected driverMode:", data[volDataKey.driverMode])
}
})
}
if csiMounter.volumeID != testVol {
t.Error("mounter volume id not set")
}
if csiMounter.pod == nil {
t.Error("mounter pod not set")
}
if csiMounter.podUID == types.UID("") {
t.Error("mounter podUID not set")
}
if csiMounter.csiClient == nil {
t.Error("mounter csiClient is nil")
}
func TestPluginNewMounterWithInline(t *testing.T) {
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIInlineVolume, true)()
tests := []struct {
name string
spec *volume.Spec
podUID types.UID
namespace string
driverMode driverMode
shouldFail bool
}{
{
name: "mounter with missing spec",
shouldFail: true,
},
{
name: "mounter with spec with both volSrc and pvSrc",
spec: &volume.Spec{
Volume: makeTestVol("test-vol1", testDriver),
PersistentVolume: makeTestPV("test-pv1", 20, testDriver, testVol),
ReadOnly: true,
},
shouldFail: true,
},
{
name: "mounter with persistent volume source",
spec: volume.NewSpecFromPersistentVolume(makeTestPV("test-pv1", 20, testDriver, testVol), true),
podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())),
namespace: "test-ns1",
driverMode: persistentDriverMode,
},
{
name: "mounter with volume source",
spec: volume.NewSpecFromVolume(makeTestVol("test-vol1", testDriver)),
podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())),
namespace: "test-ns2",
driverMode: ephemeralDriverMode,
},
}
// ensure data file is created
dataDir := path.Dir(mounter.GetPath())
dataFile := filepath.Join(dataDir, volDataFileName)
if _, err := os.Stat(dataFile); err != nil {
if os.IsNotExist(err) {
t.Errorf("data file not created %s", dataFile)
} else {
t.Fatal(err)
}
for _, test := range tests {
plug, tmpDir := newTestPlugin(t, nil)
defer os.RemoveAll(tmpDir)
registerFakePlugin(testDriver, "endpoint", []string{"1.2.0"}, t)
t.Run(test.name, func(t *testing.T) {
mounter, err := plug.NewMounter(
test.spec,
&api.Pod{ObjectMeta: meta.ObjectMeta{UID: test.podUID, Namespace: test.namespace}},
volume.VolumeOptions{},
)
if test.shouldFail != (err != nil) {
t.Fatal("Unexpected error:", err)
}
if test.shouldFail && err != nil {
t.Log(err)
return
}
if mounter == nil {
t.Fatal("failed to create CSI mounter")
}
csiMounter := mounter.(*csiMountMgr)
// validate mounter fields
if string(csiMounter.driverName) != testDriver {
t.Error("mounter driver name not set")
}
if csiMounter.volumeID == "" {
t.Error("mounter volume id not set")
}
if csiMounter.pod == nil {
t.Error("mounter pod not set")
}
if string(csiMounter.podUID) != string(test.podUID) {
t.Error("mounter podUID not set")
}
if csiMounter.csiClient == nil {
t.Error("mounter csiClient is nil")
}
if csiMounter.driverMode != test.driverMode {
t.Error("unexpected driver mode:", csiMounter.driverMode)
}
// ensure data file is created
dataDir := path.Dir(mounter.GetPath())
dataFile := filepath.Join(dataDir, volDataFileName)
if _, err := os.Stat(dataFile); err != nil {
if os.IsNotExist(err) {
t.Errorf("data file not created %s", dataFile)
} else {
t.Fatal(err)
}
}
data, err := loadVolumeData(dataDir, volDataFileName)
if err != nil {
t.Fatal(err)
}
if data[volDataKey.specVolID] != csiMounter.spec.Name() {
t.Error("volume data file unexpected specVolID:", data[volDataKey.specVolID])
}
if data[volDataKey.volHandle] != csiMounter.volumeID {
t.Error("volume data file unexpected volHandle:", data[volDataKey.volHandle])
}
if data[volDataKey.driverName] != string(csiMounter.driverName) {
t.Error("volume data file unexpected driverName:", data[volDataKey.driverName])
}
if data[volDataKey.nodeName] != string(csiMounter.plugin.host.GetNodeName()) {
t.Error("volume data file unexpected nodeName:", data[volDataKey.nodeName])
}
if data[volDataKey.driverMode] != string(csiMounter.driverMode) {
t.Error("volume data file unexpected driverMode:", data[volDataKey.driverMode])
}
})
}
}
@ -371,25 +861,36 @@ func TestPluginNewDetacher(t *testing.T) {
}
func TestPluginCanAttach(t *testing.T) {
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIDriverRegistry, true)()
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIInlineVolume, true)()
tests := []struct {
name string
driverName string
spec *volume.Spec
canAttach bool
}{
{
name: "attachable",
driverName: "attachble-driver",
name: "non-attachable inline",
driverName: "attachable-inline",
spec: volume.NewSpecFromVolume(makeTestVol("test-vol", "attachable-inline")),
canAttach: false,
},
{
name: "attachable PV",
driverName: "attachable-pv",
spec: volume.NewSpecFromPersistentVolume(makeTestPV("test-vol", 20, "attachable-pv", testVol), true),
canAttach: true,
},
}
for _, test := range tests {
csiDriver := getCSIDriver(test.driverName, nil, &test.canAttach)
t.Run(test.name, func(t *testing.T) {
plug, tmpDir := newTestPlugin(t, nil)
fakeCSIClient := fakeclient.NewSimpleClientset(csiDriver)
plug, tmpDir := newTestPlugin(t, fakeCSIClient)
defer os.RemoveAll(tmpDir)
spec := volume.NewSpecFromPersistentVolume(makeTestPV("test-pv", 10, test.driverName, "test-vol"), false)
pluginCanAttach := plug.CanAttach(spec)
pluginCanAttach := plug.CanAttach(test.spec)
if pluginCanAttach != test.canAttach {
t.Fatalf("expecting plugin.CanAttach %t got %t", test.canAttach, pluginCanAttach)
return

View File

@ -25,8 +25,10 @@ import (
api "k8s.io/api/core/v1"
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/client-go/kubernetes"
"k8s.io/klog"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/volume"
utilstrings "k8s.io/utils/strings"
)
@ -90,12 +92,7 @@ func loadVolumeData(dir string, fileName string) (map[string]string, error) {
}
func getCSISourceFromSpec(spec *volume.Spec) (*api.CSIPersistentVolumeSource, error) {
if spec.PersistentVolume != nil &&
spec.PersistentVolume.Spec.CSI != nil {
return spec.PersistentVolume.Spec.CSI, nil
}
return nil, fmt.Errorf("CSIPersistentVolumeSource not defined in spec")
return getPVSourceFromSpec(spec)
}
func getReadOnlyFromSpec(spec *volume.Spec) (bool, error) {
@ -140,3 +137,34 @@ func hasReadWriteOnce(modes []api.PersistentVolumeAccessMode) bool {
}
return false
}
// getSourceFromSpec returns either CSIVolumeSource or CSIPersistentVolumeSource, but not both
func getSourceFromSpec(spec *volume.Spec) (*api.CSIVolumeSource, *api.CSIPersistentVolumeSource, error) {
if spec == nil {
return nil, nil, fmt.Errorf("volume.Spec nil")
}
if spec.Volume != nil && spec.PersistentVolume != nil {
return nil, nil, fmt.Errorf("volume.Spec has both volume and persistent volume sources")
}
if spec.Volume != nil && spec.Volume.CSI != nil && utilfeature.DefaultFeatureGate.Enabled(features.CSIInlineVolume) {
return spec.Volume.CSI, nil, nil
}
if spec.PersistentVolume != nil &&
spec.PersistentVolume.Spec.CSI != nil {
return nil, spec.PersistentVolume.Spec.CSI, nil
}
return nil, nil, fmt.Errorf("volume source not found in volume.Spec")
}
// getPVSourceFromSpec ensures only CSIPersistentVolumeSource is present in volume.Spec
func getPVSourceFromSpec(spec *volume.Spec) (*api.CSIPersistentVolumeSource, error) {
volSrc, pvSrc, err := getSourceFromSpec(spec)
if err != nil {
return nil, err
}
if volSrc != nil {
return nil, fmt.Errorf("unexpected api.CSIVolumeSource found in volume.Spec")
}
return pvSrc, nil
}

View File

@ -57,9 +57,12 @@ func (f *IdentityClient) Probe(ctx context.Context, in *csipb.ProbeRequest, opts
}
type CSIVolume struct {
VolumeContext map[string]string
Path string
MountFlags []string
VolumeHandle string
VolumeContext map[string]string
Path string
DeviceMountPath string
FSType string
MountFlags []string
}
// NodeClient returns CSI node client
@ -118,7 +121,6 @@ func (f *NodeClient) AddNodeStagedVolume(volID, deviceMountPath string, volumeCo
// NodePublishVolume implements CSI NodePublishVolume
func (f *NodeClient) NodePublishVolume(ctx context.Context, req *csipb.NodePublishVolumeRequest, opts ...grpc.CallOption) (*csipb.NodePublishVolumeResponse, error) {
if f.nextErr != nil {
return nil, f.nextErr
}
@ -135,9 +137,12 @@ func (f *NodeClient) NodePublishVolume(ctx context.Context, req *csipb.NodePubli
return nil, errors.New("invalid fstype")
}
f.nodePublishedVolumes[req.GetVolumeId()] = CSIVolume{
Path: req.GetTargetPath(),
VolumeContext: req.GetVolumeContext(),
MountFlags: req.GetVolumeCapability().GetMount().MountFlags,
VolumeHandle: req.GetVolumeId(),
Path: req.GetTargetPath(),
DeviceMountPath: req.GetStagingTargetPath(),
VolumeContext: req.GetVolumeContext(),
FSType: req.GetVolumeCapability().GetMount().GetFsType(),
MountFlags: req.GetVolumeCapability().GetMount().MountFlags,
}
return &csipb.NodePublishVolumeResponse{}, nil
}

File diff suppressed because it is too large Load Diff

View File

@ -220,6 +220,37 @@ message CSIPersistentVolumeSource {
optional SecretReference nodePublishSecretRef = 8;
}
// Represents a source location of a volume to mount, managed by an external CSI driver
message CSIVolumeSource {
// Driver is the name of the CSI driver that handles this volume.
// Consult with your admin for the correct name as registered in the cluster.
optional string driver = 1;
// Specifies a read-only configuration for the volume.
// Defaults to false (read/write).
// +optional
optional bool readOnly = 2;
// Filesystem type to mount. Ex. "ext4", "xfs", "ntfs".
// If not provided, the empty value is passed to the associated CSI driver
// which will determine the default filesystem to apply.
// +optional
optional string fsType = 3;
// VolumeAttributes stores driver-specific properties that are passed to the CSI
// driver. Consult your driver's documentation for supported values.
// +optional
map<string, string> volumeAttributes = 4;
// NodePublishSecretRef is a reference to the secret object containing
// sensitive information to pass to the CSI driver to complete the CSI
// NodePublishVolume and NodeUnpublishVolume calls.
// This field is optional, and may be empty if no secret is required. If the
// secret object contains more than one secret, all secret references are passed.
// +optional
optional LocalObjectReference nodePublishSecretRef = 5;
}
// Adds and removes POSIX capabilities from running containers.
message Capabilities {
// Added capabilities
@ -2492,7 +2523,7 @@ message PersistentVolumeSource {
// +optional
optional StorageOSPersistentVolumeSource storageos = 21;
// CSI represents storage that handled by an external CSI driver (Beta feature).
// CSI represents storage that is handled by an external CSI driver (Beta feature).
// +optional
optional CSIPersistentVolumeSource csi = 22;
}
@ -4776,6 +4807,10 @@ message VolumeSource {
// StorageOS represents a StorageOS volume attached and mounted on Kubernetes nodes.
// +optional
optional StorageOSVolumeSource storageos = 27;
// CSI (Container Storage Interface) represents storage that is handled by an external CSI driver (Alpha feature).
// +optional
optional CSIVolumeSource csi = 28;
}
// Represents a vSphere volume resource.

View File

@ -151,6 +151,9 @@ type VolumeSource struct {
// StorageOS represents a StorageOS volume attached and mounted on Kubernetes nodes.
// +optional
StorageOS *StorageOSVolumeSource `json:"storageos,omitempty" protobuf:"bytes,27,opt,name=storageos"`
// CSI (Container Storage Interface) represents storage that is handled by an external CSI driver (Alpha feature).
// +optional
CSI *CSIVolumeSource `json:"csi,omitempty" protobuf:"bytes,28,opt,name=csi"`
}
// PersistentVolumeClaimVolumeSource references the user's PVC in the same namespace.
@ -248,7 +251,7 @@ type PersistentVolumeSource struct {
// More info: https://releases.k8s.io/HEAD/examples/volumes/storageos/README.md
// +optional
StorageOS *StorageOSPersistentVolumeSource `json:"storageos,omitempty" protobuf:"bytes,21,opt,name=storageos"`
// CSI represents storage that handled by an external CSI driver (Beta feature).
// CSI represents storage that is handled by an external CSI driver (Beta feature).
// +optional
CSI *CSIPersistentVolumeSource `json:"csi,omitempty" protobuf:"bytes,22,opt,name=csi"`
}
@ -1691,6 +1694,37 @@ type CSIPersistentVolumeSource struct {
NodePublishSecretRef *SecretReference `json:"nodePublishSecretRef,omitempty" protobuf:"bytes,8,opt,name=nodePublishSecretRef"`
}
// Represents a source location of a volume to mount, managed by an external CSI driver
type CSIVolumeSource struct {
// Driver is the name of the CSI driver that handles this volume.
// Consult with your admin for the correct name as registered in the cluster.
Driver string `json:"driver" protobuf:"bytes,1,opt,name=driver"`
// Specifies a read-only configuration for the volume.
// Defaults to false (read/write).
// +optional
ReadOnly *bool `json:"readOnly,omitempty" protobuf:"varint,2,opt,name=readOnly"`
// Filesystem type to mount. Ex. "ext4", "xfs", "ntfs".
// If not provided, the empty value is passed to the associated CSI driver
// which will determine the default filesystem to apply.
// +optional
FSType *string `json:"fsType,omitempty" protobuf:"bytes,3,opt,name=fsType"`
// VolumeAttributes stores driver-specific properties that are passed to the CSI
// driver. Consult your driver's documentation for supported values.
// +optional
VolumeAttributes map[string]string `json:"volumeAttributes,omitempty" protobuf:"bytes,4,rep,name=volumeAttributes"`
// NodePublishSecretRef is a reference to the secret object containing
// sensitive information to pass to the CSI driver to complete the CSI
// NodePublishVolume and NodeUnpublishVolume calls.
// This field is optional, and may be empty if no secret is required. If the
// secret object contains more than one secret, all secret references are passed.
// +optional
NodePublishSecretRef *LocalObjectReference `json:"nodePublishSecretRef,omitempty" protobuf:"bytes,5,opt,name=nodePublishSecretRef"`
}
// ContainerPort represents a network port in a single container.
type ContainerPort struct {
// If specified, this must be an IANA_SVC_NAME and unique within the pod. Each

View File

@ -132,6 +132,19 @@ func (CSIPersistentVolumeSource) SwaggerDoc() map[string]string {
return map_CSIPersistentVolumeSource
}
var map_CSIVolumeSource = map[string]string{
"": "Represents a source location of a volume to mount, managed by an external CSI driver",
"driver": "Driver is the name of the CSI driver that handles this volume. Consult with your admin for the correct name as registered in the cluster.",
"readOnly": "Specifies a read-only configuration for the volume. Defaults to false (read/write).",
"fsType": "Filesystem type to mount. Ex. \"ext4\", \"xfs\", \"ntfs\". If not provided, the empty value is passed to the associated CSI driver which will determine the default filesystem to apply.",
"volumeAttributes": "VolumeAttributes stores driver-specific properties that are passed to the CSI driver. Consult your driver's documentation for supported values.",
"nodePublishSecretRef": "NodePublishSecretRef is a reference to the secret object containing sensitive information to pass to the CSI driver to complete the CSI NodePublishVolume and NodeUnpublishVolume calls. This field is optional, and may be empty if no secret is required. If the secret object contains more than one secret, all secret references are passed.",
}
func (CSIVolumeSource) SwaggerDoc() map[string]string {
return map_CSIVolumeSource
}
var map_Capabilities = map[string]string{
"": "Adds and removes POSIX capabilities from running containers.",
"add": "Added capabilities",
@ -1285,7 +1298,7 @@ var map_PersistentVolumeSource = map[string]string{
"scaleIO": "ScaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes.",
"local": "Local represents directly-attached storage with node affinity",
"storageos": "StorageOS represents a StorageOS volume that is attached to the kubelet's host machine and mounted into the pod More info: https://releases.k8s.io/HEAD/examples/volumes/storageos/README.md",
"csi": "CSI represents storage that handled by an external CSI driver (Beta feature).",
"csi": "CSI represents storage that is handled by an external CSI driver (Beta feature).",
}
func (PersistentVolumeSource) SwaggerDoc() map[string]string {
@ -2317,6 +2330,7 @@ var map_VolumeSource = map[string]string{
"portworxVolume": "PortworxVolume represents a portworx volume attached and mounted on kubelets host machine",
"scaleIO": "ScaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes.",
"storageos": "StorageOS represents a StorageOS volume attached and mounted on Kubernetes nodes.",
"csi": "CSI (Container Storage Interface) represents storage that is handled by an external CSI driver (Alpha feature).",
}
func (VolumeSource) SwaggerDoc() map[string]string {

View File

@ -250,6 +250,44 @@ func (in *CSIPersistentVolumeSource) DeepCopy() *CSIPersistentVolumeSource {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CSIVolumeSource) DeepCopyInto(out *CSIVolumeSource) {
*out = *in
if in.ReadOnly != nil {
in, out := &in.ReadOnly, &out.ReadOnly
*out = new(bool)
**out = **in
}
if in.FSType != nil {
in, out := &in.FSType, &out.FSType
*out = new(string)
**out = **in
}
if in.VolumeAttributes != nil {
in, out := &in.VolumeAttributes, &out.VolumeAttributes
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
if in.NodePublishSecretRef != nil {
in, out := &in.NodePublishSecretRef, &out.NodePublishSecretRef
*out = new(LocalObjectReference)
**out = **in
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSIVolumeSource.
func (in *CSIVolumeSource) DeepCopy() *CSIVolumeSource {
if in == nil {
return nil
}
out := new(CSIVolumeSource)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Capabilities) DeepCopyInto(out *Capabilities) {
*out = *in
@ -5383,6 +5421,11 @@ func (in *VolumeSource) DeepCopyInto(out *VolumeSource) {
*out = new(StorageOSVolumeSource)
(*in).DeepCopyInto(*out)
}
if in.CSI != nil {
in, out := &in.CSI, &out.CSI
*out = new(CSIVolumeSource)
(*in).DeepCopyInto(*out)
}
return
}

View File

@ -24,6 +24,7 @@ limitations under the License.
k8s.io/kubernetes/vendor/k8s.io/api/extensions/v1beta1/generated.proto
It has these top-level messages:
AllowedCSIDriver
AllowedFlexVolume
AllowedHostPath
DaemonSet
@ -109,241 +110,246 @@ var _ = math.Inf
// proto package needs to be updated.
const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
func (m *AllowedCSIDriver) Reset() { *m = AllowedCSIDriver{} }
func (*AllowedCSIDriver) ProtoMessage() {}
func (*AllowedCSIDriver) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{0} }
func (m *AllowedFlexVolume) Reset() { *m = AllowedFlexVolume{} }
func (*AllowedFlexVolume) ProtoMessage() {}
func (*AllowedFlexVolume) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{0} }
func (*AllowedFlexVolume) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{1} }
func (m *AllowedHostPath) Reset() { *m = AllowedHostPath{} }
func (*AllowedHostPath) ProtoMessage() {}
func (*AllowedHostPath) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{1} }
func (*AllowedHostPath) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{2} }
func (m *DaemonSet) Reset() { *m = DaemonSet{} }
func (*DaemonSet) ProtoMessage() {}
func (*DaemonSet) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{2} }
func (*DaemonSet) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{3} }
func (m *DaemonSetCondition) Reset() { *m = DaemonSetCondition{} }
func (*DaemonSetCondition) ProtoMessage() {}
func (*DaemonSetCondition) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{3} }
func (*DaemonSetCondition) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{4} }
func (m *DaemonSetList) Reset() { *m = DaemonSetList{} }
func (*DaemonSetList) ProtoMessage() {}
func (*DaemonSetList) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{4} }
func (*DaemonSetList) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{5} }
func (m *DaemonSetSpec) Reset() { *m = DaemonSetSpec{} }
func (*DaemonSetSpec) ProtoMessage() {}
func (*DaemonSetSpec) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{5} }
func (*DaemonSetSpec) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{6} }
func (m *DaemonSetStatus) Reset() { *m = DaemonSetStatus{} }
func (*DaemonSetStatus) ProtoMessage() {}
func (*DaemonSetStatus) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{6} }
func (*DaemonSetStatus) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{7} }
func (m *DaemonSetUpdateStrategy) Reset() { *m = DaemonSetUpdateStrategy{} }
func (*DaemonSetUpdateStrategy) ProtoMessage() {}
func (*DaemonSetUpdateStrategy) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{7} }
func (*DaemonSetUpdateStrategy) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{8} }
func (m *Deployment) Reset() { *m = Deployment{} }
func (*Deployment) ProtoMessage() {}
func (*Deployment) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{8} }
func (*Deployment) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{9} }
func (m *DeploymentCondition) Reset() { *m = DeploymentCondition{} }
func (*DeploymentCondition) ProtoMessage() {}
func (*DeploymentCondition) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{9} }
func (*DeploymentCondition) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{10} }
func (m *DeploymentList) Reset() { *m = DeploymentList{} }
func (*DeploymentList) ProtoMessage() {}
func (*DeploymentList) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{10} }
func (*DeploymentList) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{11} }
func (m *DeploymentRollback) Reset() { *m = DeploymentRollback{} }
func (*DeploymentRollback) ProtoMessage() {}
func (*DeploymentRollback) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{11} }
func (*DeploymentRollback) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{12} }
func (m *DeploymentSpec) Reset() { *m = DeploymentSpec{} }
func (*DeploymentSpec) ProtoMessage() {}
func (*DeploymentSpec) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{12} }
func (*DeploymentSpec) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{13} }
func (m *DeploymentStatus) Reset() { *m = DeploymentStatus{} }
func (*DeploymentStatus) ProtoMessage() {}
func (*DeploymentStatus) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{13} }
func (*DeploymentStatus) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{14} }
func (m *DeploymentStrategy) Reset() { *m = DeploymentStrategy{} }
func (*DeploymentStrategy) ProtoMessage() {}
func (*DeploymentStrategy) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{14} }
func (*DeploymentStrategy) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{15} }
func (m *FSGroupStrategyOptions) Reset() { *m = FSGroupStrategyOptions{} }
func (*FSGroupStrategyOptions) ProtoMessage() {}
func (*FSGroupStrategyOptions) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{15} }
func (*FSGroupStrategyOptions) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{16} }
func (m *HTTPIngressPath) Reset() { *m = HTTPIngressPath{} }
func (*HTTPIngressPath) ProtoMessage() {}
func (*HTTPIngressPath) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{16} }
func (*HTTPIngressPath) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{17} }
func (m *HTTPIngressRuleValue) Reset() { *m = HTTPIngressRuleValue{} }
func (*HTTPIngressRuleValue) ProtoMessage() {}
func (*HTTPIngressRuleValue) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{17} }
func (*HTTPIngressRuleValue) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{18} }
func (m *HostPortRange) Reset() { *m = HostPortRange{} }
func (*HostPortRange) ProtoMessage() {}
func (*HostPortRange) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{18} }
func (*HostPortRange) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{19} }
func (m *IDRange) Reset() { *m = IDRange{} }
func (*IDRange) ProtoMessage() {}
func (*IDRange) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{19} }
func (*IDRange) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{20} }
func (m *IPBlock) Reset() { *m = IPBlock{} }
func (*IPBlock) ProtoMessage() {}
func (*IPBlock) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{20} }
func (*IPBlock) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{21} }
func (m *Ingress) Reset() { *m = Ingress{} }
func (*Ingress) ProtoMessage() {}
func (*Ingress) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{21} }
func (*Ingress) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{22} }
func (m *IngressBackend) Reset() { *m = IngressBackend{} }
func (*IngressBackend) ProtoMessage() {}
func (*IngressBackend) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{22} }
func (*IngressBackend) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{23} }
func (m *IngressList) Reset() { *m = IngressList{} }
func (*IngressList) ProtoMessage() {}
func (*IngressList) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{23} }
func (*IngressList) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{24} }
func (m *IngressRule) Reset() { *m = IngressRule{} }
func (*IngressRule) ProtoMessage() {}
func (*IngressRule) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{24} }
func (*IngressRule) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{25} }
func (m *IngressRuleValue) Reset() { *m = IngressRuleValue{} }
func (*IngressRuleValue) ProtoMessage() {}
func (*IngressRuleValue) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{25} }
func (*IngressRuleValue) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{26} }
func (m *IngressSpec) Reset() { *m = IngressSpec{} }
func (*IngressSpec) ProtoMessage() {}
func (*IngressSpec) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{26} }
func (*IngressSpec) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{27} }
func (m *IngressStatus) Reset() { *m = IngressStatus{} }
func (*IngressStatus) ProtoMessage() {}
func (*IngressStatus) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{27} }
func (*IngressStatus) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{28} }
func (m *IngressTLS) Reset() { *m = IngressTLS{} }
func (*IngressTLS) ProtoMessage() {}
func (*IngressTLS) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{28} }
func (*IngressTLS) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{29} }
func (m *NetworkPolicy) Reset() { *m = NetworkPolicy{} }
func (*NetworkPolicy) ProtoMessage() {}
func (*NetworkPolicy) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{29} }
func (*NetworkPolicy) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{30} }
func (m *NetworkPolicyEgressRule) Reset() { *m = NetworkPolicyEgressRule{} }
func (*NetworkPolicyEgressRule) ProtoMessage() {}
func (*NetworkPolicyEgressRule) Descriptor() ([]byte, []int) {
return fileDescriptorGenerated, []int{30}
return fileDescriptorGenerated, []int{31}
}
func (m *NetworkPolicyIngressRule) Reset() { *m = NetworkPolicyIngressRule{} }
func (*NetworkPolicyIngressRule) ProtoMessage() {}
func (*NetworkPolicyIngressRule) Descriptor() ([]byte, []int) {
return fileDescriptorGenerated, []int{31}
return fileDescriptorGenerated, []int{32}
}
func (m *NetworkPolicyList) Reset() { *m = NetworkPolicyList{} }
func (*NetworkPolicyList) ProtoMessage() {}
func (*NetworkPolicyList) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{32} }
func (*NetworkPolicyList) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{33} }
func (m *NetworkPolicyPeer) Reset() { *m = NetworkPolicyPeer{} }
func (*NetworkPolicyPeer) ProtoMessage() {}
func (*NetworkPolicyPeer) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{33} }
func (*NetworkPolicyPeer) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{34} }
func (m *NetworkPolicyPort) Reset() { *m = NetworkPolicyPort{} }
func (*NetworkPolicyPort) ProtoMessage() {}
func (*NetworkPolicyPort) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{34} }
func (*NetworkPolicyPort) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{35} }
func (m *NetworkPolicySpec) Reset() { *m = NetworkPolicySpec{} }
func (*NetworkPolicySpec) ProtoMessage() {}
func (*NetworkPolicySpec) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{35} }
func (*NetworkPolicySpec) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{36} }
func (m *PodSecurityPolicy) Reset() { *m = PodSecurityPolicy{} }
func (*PodSecurityPolicy) ProtoMessage() {}
func (*PodSecurityPolicy) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{36} }
func (*PodSecurityPolicy) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{37} }
func (m *PodSecurityPolicyList) Reset() { *m = PodSecurityPolicyList{} }
func (*PodSecurityPolicyList) ProtoMessage() {}
func (*PodSecurityPolicyList) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{37} }
func (*PodSecurityPolicyList) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{38} }
func (m *PodSecurityPolicySpec) Reset() { *m = PodSecurityPolicySpec{} }
func (*PodSecurityPolicySpec) ProtoMessage() {}
func (*PodSecurityPolicySpec) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{38} }
func (*PodSecurityPolicySpec) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{39} }
func (m *ReplicaSet) Reset() { *m = ReplicaSet{} }
func (*ReplicaSet) ProtoMessage() {}
func (*ReplicaSet) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{39} }
func (*ReplicaSet) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{40} }
func (m *ReplicaSetCondition) Reset() { *m = ReplicaSetCondition{} }
func (*ReplicaSetCondition) ProtoMessage() {}
func (*ReplicaSetCondition) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{40} }
func (*ReplicaSetCondition) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{41} }
func (m *ReplicaSetList) Reset() { *m = ReplicaSetList{} }
func (*ReplicaSetList) ProtoMessage() {}
func (*ReplicaSetList) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{41} }
func (*ReplicaSetList) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{42} }
func (m *ReplicaSetSpec) Reset() { *m = ReplicaSetSpec{} }
func (*ReplicaSetSpec) ProtoMessage() {}
func (*ReplicaSetSpec) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{42} }
func (*ReplicaSetSpec) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{43} }
func (m *ReplicaSetStatus) Reset() { *m = ReplicaSetStatus{} }
func (*ReplicaSetStatus) ProtoMessage() {}
func (*ReplicaSetStatus) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{43} }
func (*ReplicaSetStatus) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{44} }
func (m *ReplicationControllerDummy) Reset() { *m = ReplicationControllerDummy{} }
func (*ReplicationControllerDummy) ProtoMessage() {}
func (*ReplicationControllerDummy) Descriptor() ([]byte, []int) {
return fileDescriptorGenerated, []int{44}
return fileDescriptorGenerated, []int{45}
}
func (m *RollbackConfig) Reset() { *m = RollbackConfig{} }
func (*RollbackConfig) ProtoMessage() {}
func (*RollbackConfig) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{45} }
func (*RollbackConfig) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{46} }
func (m *RollingUpdateDaemonSet) Reset() { *m = RollingUpdateDaemonSet{} }
func (*RollingUpdateDaemonSet) ProtoMessage() {}
func (*RollingUpdateDaemonSet) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{46} }
func (*RollingUpdateDaemonSet) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{47} }
func (m *RollingUpdateDeployment) Reset() { *m = RollingUpdateDeployment{} }
func (*RollingUpdateDeployment) ProtoMessage() {}
func (*RollingUpdateDeployment) Descriptor() ([]byte, []int) {
return fileDescriptorGenerated, []int{47}
return fileDescriptorGenerated, []int{48}
}
func (m *RunAsGroupStrategyOptions) Reset() { *m = RunAsGroupStrategyOptions{} }
func (*RunAsGroupStrategyOptions) ProtoMessage() {}
func (*RunAsGroupStrategyOptions) Descriptor() ([]byte, []int) {
return fileDescriptorGenerated, []int{48}
return fileDescriptorGenerated, []int{49}
}
func (m *RunAsUserStrategyOptions) Reset() { *m = RunAsUserStrategyOptions{} }
func (*RunAsUserStrategyOptions) ProtoMessage() {}
func (*RunAsUserStrategyOptions) Descriptor() ([]byte, []int) {
return fileDescriptorGenerated, []int{49}
return fileDescriptorGenerated, []int{50}
}
func (m *SELinuxStrategyOptions) Reset() { *m = SELinuxStrategyOptions{} }
func (*SELinuxStrategyOptions) ProtoMessage() {}
func (*SELinuxStrategyOptions) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{50} }
func (*SELinuxStrategyOptions) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{51} }
func (m *Scale) Reset() { *m = Scale{} }
func (*Scale) ProtoMessage() {}
func (*Scale) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{51} }
func (*Scale) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{52} }
func (m *ScaleSpec) Reset() { *m = ScaleSpec{} }
func (*ScaleSpec) ProtoMessage() {}
func (*ScaleSpec) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{52} }
func (*ScaleSpec) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{53} }
func (m *ScaleStatus) Reset() { *m = ScaleStatus{} }
func (*ScaleStatus) ProtoMessage() {}
func (*ScaleStatus) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{53} }
func (*ScaleStatus) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{54} }
func (m *SupplementalGroupsStrategyOptions) Reset() { *m = SupplementalGroupsStrategyOptions{} }
func (*SupplementalGroupsStrategyOptions) ProtoMessage() {}
func (*SupplementalGroupsStrategyOptions) Descriptor() ([]byte, []int) {
return fileDescriptorGenerated, []int{54}
return fileDescriptorGenerated, []int{55}
}
func init() {
proto.RegisterType((*AllowedCSIDriver)(nil), "k8s.io.api.extensions.v1beta1.AllowedCSIDriver")
proto.RegisterType((*AllowedFlexVolume)(nil), "k8s.io.api.extensions.v1beta1.AllowedFlexVolume")
proto.RegisterType((*AllowedHostPath)(nil), "k8s.io.api.extensions.v1beta1.AllowedHostPath")
proto.RegisterType((*DaemonSet)(nil), "k8s.io.api.extensions.v1beta1.DaemonSet")
@ -400,6 +406,28 @@ func init() {
proto.RegisterType((*ScaleStatus)(nil), "k8s.io.api.extensions.v1beta1.ScaleStatus")
proto.RegisterType((*SupplementalGroupsStrategyOptions)(nil), "k8s.io.api.extensions.v1beta1.SupplementalGroupsStrategyOptions")
}
func (m *AllowedCSIDriver) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *AllowedCSIDriver) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
dAtA[i] = 0xa
i++
i = encodeVarintGenerated(dAtA, i, uint64(len(m.Name)))
i += copy(dAtA[i:], m.Name)
return i, nil
}
func (m *AllowedFlexVolume) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
@ -2176,6 +2204,20 @@ func (m *PodSecurityPolicySpec) MarshalTo(dAtA []byte) (int, error) {
}
i += n47
}
if len(m.AllowedCSIDrivers) > 0 {
for _, msg := range m.AllowedCSIDrivers {
dAtA[i] = 0xba
i++
dAtA[i] = 0x1
i++
i = encodeVarintGenerated(dAtA, i, uint64(msg.Size()))
n, err := msg.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n
}
}
return i, nil
}
@ -2748,6 +2790,14 @@ func encodeVarintGenerated(dAtA []byte, offset int, v uint64) int {
dAtA[offset] = uint8(v)
return offset + 1
}
func (m *AllowedCSIDriver) Size() (n int) {
var l int
_ = l
l = len(m.Name)
n += 1 + l + sovGenerated(uint64(l))
return n
}
func (m *AllowedFlexVolume) Size() (n int) {
var l int
_ = l
@ -3379,6 +3429,12 @@ func (m *PodSecurityPolicySpec) Size() (n int) {
l = m.RunAsGroup.Size()
n += 2 + l + sovGenerated(uint64(l))
}
if len(m.AllowedCSIDrivers) > 0 {
for _, e := range m.AllowedCSIDrivers {
l = e.Size()
n += 2 + l + sovGenerated(uint64(l))
}
}
return n
}
@ -3597,6 +3653,16 @@ func sovGenerated(x uint64) (n int) {
func sozGenerated(x uint64) (n int) {
return sovGenerated(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (this *AllowedCSIDriver) String() string {
if this == nil {
return "nil"
}
s := strings.Join([]string{`&AllowedCSIDriver{`,
`Name:` + fmt.Sprintf("%v", this.Name) + `,`,
`}`,
}, "")
return s
}
func (this *AllowedFlexVolume) String() string {
if this == nil {
return "nil"
@ -4088,6 +4154,7 @@ func (this *PodSecurityPolicySpec) String() string {
`ForbiddenSysctls:` + fmt.Sprintf("%v", this.ForbiddenSysctls) + `,`,
`AllowedProcMountTypes:` + fmt.Sprintf("%v", this.AllowedProcMountTypes) + `,`,
`RunAsGroup:` + strings.Replace(fmt.Sprintf("%v", this.RunAsGroup), "RunAsGroupStrategyOptions", "RunAsGroupStrategyOptions", 1) + `,`,
`AllowedCSIDrivers:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.AllowedCSIDrivers), "AllowedCSIDriver", "AllowedCSIDriver", 1), `&`, ``, 1) + `,`,
`}`,
}, "")
return s
@ -4293,6 +4360,85 @@ func valueToStringGenerated(v interface{}) string {
pv := reflect.Indirect(rv).Interface()
return fmt.Sprintf("*%v", pv)
}
func (m *AllowedCSIDriver) 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: AllowedCSIDriver: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: AllowedCSIDriver: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Name", 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 > l {
return io.ErrUnexpectedEOF
}
m.Name = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipGenerated(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthGenerated
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *AllowedFlexVolume) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
@ -9978,6 +10124,37 @@ func (m *PodSecurityPolicySpec) Unmarshal(dAtA []byte) error {
return err
}
iNdEx = postIndex
case 23:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field AllowedCSIDrivers", 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 > l {
return io.ErrUnexpectedEOF
}
m.AllowedCSIDrivers = append(m.AllowedCSIDrivers, AllowedCSIDriver{})
if err := m.AllowedCSIDrivers[len(m.AllowedCSIDrivers)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipGenerated(dAtA[iNdEx:])
@ -12069,230 +12246,232 @@ func init() {
}
var fileDescriptorGenerated = []byte{
// 3587 bytes of a gzipped FileDescriptorProto
// 3622 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x5b, 0xcd, 0x6f, 0x1c, 0x47,
0x76, 0x57, 0xcf, 0x0c, 0x39, 0xc3, 0x47, 0xf1, 0xab, 0x48, 0x91, 0x63, 0xc9, 0xe2, 0xc8, 0x6d,
0x40, 0x91, 0x1d, 0x69, 0xc6, 0x92, 0x2d, 0x59, 0xb1, 0x10, 0xdb, 0x1c, 0x52, 0x94, 0xe8, 0xf0,
0x40, 0x91, 0x1d, 0x69, 0xc6, 0x92, 0x25, 0x59, 0xb1, 0x10, 0xdb, 0x1c, 0x52, 0x94, 0xe8, 0xf0,
0x63, 0x5c, 0x43, 0x2a, 0x86, 0x11, 0x3b, 0x6e, 0xce, 0x14, 0x87, 0x2d, 0xf6, 0x74, 0xb7, 0xbb,
0x6b, 0x68, 0x0e, 0x90, 0x43, 0x0e, 0x49, 0x80, 0x00, 0x09, 0x92, 0x8b, 0x93, 0x1c, 0x63, 0x04,
0xc8, 0x69, 0x17, 0xbb, 0xb7, 0xdd, 0x83, 0x61, 0x60, 0x01, 0x2f, 0x20, 0x2c, 0xbc, 0x80, 0x6f,
0xeb, 0x13, 0xb1, 0xa6, 0x4f, 0x8b, 0xfd, 0x07, 0x16, 0x3a, 0x2c, 0x16, 0x55, 0x5d, 0xfd, 0xdd,
0xad, 0x69, 0xd2, 0x12, 0xb1, 0x58, 0xec, 0x8d, 0x53, 0xef, 0xbd, 0xdf, 0x7b, 0x55, 0xf5, 0xea,
0xbd, 0xd7, 0x55, 0x8f, 0xb0, 0xbc, 0x77, 0xdb, 0xae, 0xaa, 0x46, 0x6d, 0xaf, 0xb7, 0x4d, 0x2c,
0x9d, 0x50, 0x62, 0xd7, 0xf6, 0x89, 0xde, 0x36, 0xac, 0x9a, 0x20, 0x28, 0xa6, 0x5a, 0x23, 0x07,
0x94, 0xe8, 0xb6, 0x6a, 0xe8, 0x76, 0x6d, 0xff, 0xfa, 0x36, 0xa1, 0xca, 0xf5, 0x5a, 0x87, 0xe8,
0xc4, 0x52, 0x28, 0x69, 0x57, 0x4d, 0xcb, 0xa0, 0x06, 0xba, 0xe8, 0xb0, 0x57, 0x15, 0x53, 0xad,
0xfa, 0xec, 0x55, 0xc1, 0x7e, 0xfe, 0x5a, 0x47, 0xa5, 0xbb, 0xbd, 0xed, 0x6a, 0xcb, 0xe8, 0xd6,
0x3a, 0x46, 0xc7, 0xa8, 0x71, 0xa9, 0xed, 0xde, 0x0e, 0xff, 0xc5, 0x7f, 0xf0, 0xbf, 0x1c, 0xb4,
0xf3, 0x72, 0x40, 0x79, 0xcb, 0xb0, 0x48, 0x6d, 0x3f, 0xa6, 0xf1, 0xfc, 0x6b, 0x3e, 0x4f, 0x57,
0x69, 0xed, 0xaa, 0x3a, 0xb1, 0xfa, 0x35, 0x73, 0xaf, 0xc3, 0x06, 0xec, 0x5a, 0x97, 0x50, 0x25,
0x49, 0xaa, 0x96, 0x26, 0x65, 0xf5, 0x74, 0xaa, 0x76, 0x49, 0x4c, 0xe0, 0xd6, 0x20, 0x01, 0xbb,
0xb5, 0x4b, 0xba, 0x4a, 0x4c, 0xee, 0xd5, 0x34, 0xb9, 0x1e, 0x55, 0xb5, 0x9a, 0xaa, 0x53, 0x9b,
0x5a, 0x51, 0x21, 0xf9, 0x0e, 0x4c, 0x2d, 0x68, 0x9a, 0xf1, 0x09, 0x69, 0x2f, 0x6b, 0xe4, 0xe0,
0x81, 0xa1, 0xf5, 0xba, 0x04, 0x5d, 0x86, 0xe1, 0xb6, 0xa5, 0xee, 0x13, 0xab, 0x2c, 0x5d, 0x92,
0xae, 0x8c, 0xd4, 0xc7, 0x1f, 0x1d, 0x56, 0xce, 0x1c, 0x1d, 0x56, 0x86, 0x97, 0xf8, 0x28, 0x16,
0x54, 0xd9, 0x86, 0x09, 0x21, 0x7c, 0xdf, 0xb0, 0x69, 0x43, 0xa1, 0xbb, 0xe8, 0x06, 0x80, 0xa9,
0xd0, 0xdd, 0x86, 0x45, 0x76, 0xd4, 0x03, 0x21, 0x8e, 0x84, 0x38, 0x34, 0x3c, 0x0a, 0x0e, 0x70,
0xa1, 0xab, 0x50, 0xb2, 0x88, 0xd2, 0xde, 0xd0, 0xb5, 0x7e, 0x39, 0x77, 0x49, 0xba, 0x52, 0xaa,
0x4f, 0x0a, 0x89, 0x12, 0x16, 0xe3, 0xd8, 0xe3, 0x90, 0x3f, 0xcd, 0xc1, 0xc8, 0x92, 0x42, 0xba,
0x86, 0xde, 0x24, 0x14, 0x7d, 0x04, 0x25, 0xb6, 0xf0, 0x6d, 0x85, 0x2a, 0x5c, 0xdb, 0xe8, 0x8d,
0x57, 0xaa, 0xbe, 0x63, 0x78, 0xeb, 0x50, 0x35, 0xf7, 0x3a, 0x6c, 0xc0, 0xae, 0x32, 0xee, 0xea,
0xfe, 0xf5, 0xea, 0xc6, 0xf6, 0x43, 0xd2, 0xa2, 0x6b, 0x84, 0x2a, 0xbe, 0x7d, 0xfe, 0x18, 0xf6,
0x50, 0xd1, 0x3a, 0x14, 0x6c, 0x93, 0xb4, 0xb8, 0x65, 0xa3, 0x37, 0xae, 0x56, 0x9f, 0xe8, 0x76,
0x55, 0xcf, 0xb2, 0xa6, 0x49, 0x5a, 0xf5, 0xb3, 0x02, 0xb9, 0xc0, 0x7e, 0x61, 0x8e, 0x83, 0x1e,
0xc0, 0xb0, 0x4d, 0x15, 0xda, 0xb3, 0xcb, 0x79, 0x8e, 0x58, 0xcd, 0x8c, 0xc8, 0xa5, 0xfc, 0xcd,
0x70, 0x7e, 0x63, 0x81, 0x26, 0xff, 0x26, 0x07, 0xc8, 0xe3, 0x5d, 0x34, 0xf4, 0xb6, 0x4a, 0x55,
0x43, 0x47, 0x6f, 0x40, 0x81, 0xf6, 0x4d, 0x22, 0xb6, 0xe2, 0xb2, 0x6b, 0xd0, 0x66, 0xdf, 0x24,
0x8f, 0x0f, 0x2b, 0xb3, 0x71, 0x09, 0x46, 0xc1, 0x5c, 0x06, 0xad, 0x7a, 0xa6, 0xe6, 0xb8, 0xf4,
0x6b, 0x61, 0xd5, 0x8f, 0x0f, 0x2b, 0x09, 0xc7, 0xa6, 0xea, 0x21, 0x85, 0x0d, 0x44, 0xfb, 0x80,
0x34, 0xc5, 0xa6, 0x9b, 0x96, 0xa2, 0xdb, 0x8e, 0x26, 0xb5, 0x4b, 0xc4, 0x22, 0xbc, 0x9c, 0x6d,
0xd3, 0x98, 0x44, 0xfd, 0xbc, 0xb0, 0x02, 0xad, 0xc6, 0xd0, 0x70, 0x82, 0x06, 0xe6, 0xcd, 0x16,
0x51, 0x6c, 0x43, 0x2f, 0x17, 0xc2, 0xde, 0x8c, 0xf9, 0x28, 0x16, 0x54, 0xf4, 0x12, 0x14, 0xbb,
0xc4, 0xb6, 0x95, 0x0e, 0x29, 0x0f, 0x71, 0xc6, 0x09, 0xc1, 0x58, 0x5c, 0x73, 0x86, 0xb1, 0x4b,
0x97, 0x3f, 0x97, 0x60, 0xcc, 0x5b, 0xb9, 0x55, 0xd5, 0xa6, 0xe8, 0xef, 0x62, 0x7e, 0x58, 0xcd,
0x36, 0x25, 0x26, 0xcd, 0xbd, 0xd0, 0xf3, 0x79, 0x77, 0x24, 0xe0, 0x83, 0x6b, 0x30, 0xa4, 0x52,
0xd2, 0x65, 0xfb, 0x90, 0xbf, 0x32, 0x7a, 0xe3, 0x4a, 0x56, 0x97, 0xa9, 0x8f, 0x09, 0xd0, 0xa1,
0x15, 0x26, 0x8e, 0x1d, 0x14, 0xf9, 0xbf, 0x0a, 0x01, 0xf3, 0x99, 0x6b, 0xa2, 0x0f, 0xa0, 0x64,
0x13, 0x8d, 0xb4, 0xa8, 0x61, 0x09, 0xf3, 0x5f, 0xcd, 0x68, 0xbe, 0xb2, 0x4d, 0xb4, 0xa6, 0x10,
0xad, 0x9f, 0x65, 0xf6, 0xbb, 0xbf, 0xb0, 0x07, 0x89, 0xde, 0x85, 0x12, 0x25, 0x5d, 0x53, 0x53,
0x28, 0x11, 0xe7, 0xe8, 0xc5, 0xe0, 0x14, 0x98, 0xe7, 0x30, 0xb0, 0x86, 0xd1, 0xde, 0x14, 0x6c,
0xfc, 0xf8, 0x78, 0x4b, 0xe2, 0x8e, 0x62, 0x0f, 0x06, 0xed, 0xc3, 0x78, 0xcf, 0x6c, 0x33, 0x4e,
0xca, 0xe2, 0x59, 0xa7, 0x2f, 0x3c, 0xe9, 0x56, 0xd6, 0xb5, 0xd9, 0x0a, 0x49, 0xd7, 0x67, 0x85,
0xae, 0xf1, 0xf0, 0x38, 0x8e, 0x68, 0x41, 0x0b, 0x30, 0xd1, 0x55, 0x75, 0x16, 0x97, 0xfa, 0x4d,
0xd2, 0x32, 0xf4, 0xb6, 0xcd, 0xdd, 0x6a, 0xa8, 0x3e, 0x27, 0x00, 0x26, 0xd6, 0xc2, 0x64, 0x1c,
0xe5, 0x47, 0xef, 0x00, 0x72, 0xa7, 0x71, 0xcf, 0x09, 0xc7, 0xaa, 0xa1, 0x73, 0x9f, 0xcb, 0xfb,
0xce, 0xbd, 0x19, 0xe3, 0xc0, 0x09, 0x52, 0x68, 0x15, 0x66, 0x2c, 0xb2, 0xaf, 0xb2, 0x39, 0xde,
0x57, 0x6d, 0x6a, 0x58, 0xfd, 0x55, 0xb5, 0xab, 0xd2, 0xf2, 0x30, 0xb7, 0xa9, 0x7c, 0x74, 0x58,
0x99, 0xc1, 0x09, 0x74, 0x9c, 0x28, 0x25, 0xff, 0xf7, 0x30, 0x4c, 0x44, 0xe2, 0x0d, 0x7a, 0x00,
0xb3, 0xad, 0x9e, 0x65, 0x11, 0x9d, 0xae, 0xf7, 0xba, 0xdb, 0xc4, 0x6a, 0xb6, 0x76, 0x49, 0xbb,
0xa7, 0x91, 0x36, 0x77, 0x94, 0xa1, 0xfa, 0xbc, 0xb0, 0x78, 0x76, 0x31, 0x91, 0x0b, 0xa7, 0x48,
0xb3, 0x55, 0xd0, 0xf9, 0xd0, 0x9a, 0x6a, 0xdb, 0x1e, 0x66, 0x8e, 0x63, 0x7a, 0xab, 0xb0, 0x1e,
0xe3, 0xc0, 0x09, 0x52, 0xcc, 0xc6, 0x36, 0xb1, 0x55, 0x8b, 0xb4, 0xa3, 0x36, 0xe6, 0xc3, 0x36,
0x2e, 0x25, 0x72, 0xe1, 0x14, 0x69, 0x74, 0x13, 0x46, 0x1d, 0x6d, 0x7c, 0xff, 0xc4, 0x46, 0x4f,
0x0b, 0xb0, 0xd1, 0x75, 0x9f, 0x84, 0x83, 0x7c, 0x6c, 0x6a, 0xc6, 0xb6, 0x4d, 0xac, 0x7d, 0xd2,
0x4e, 0xdf, 0xe0, 0x8d, 0x18, 0x07, 0x4e, 0x90, 0x62, 0x53, 0x73, 0x3c, 0x30, 0x36, 0xb5, 0xe1,
0xf0, 0xd4, 0xb6, 0x12, 0xb9, 0x70, 0x8a, 0x34, 0xf3, 0x63, 0xc7, 0xe4, 0x85, 0x7d, 0x45, 0xd5,
0x94, 0x6d, 0x8d, 0x94, 0x8b, 0x61, 0x3f, 0x5e, 0x0f, 0x93, 0x71, 0x94, 0x1f, 0xdd, 0x83, 0x29,
0x67, 0x68, 0x4b, 0x57, 0x3c, 0x90, 0x12, 0x07, 0x79, 0x4e, 0x80, 0x4c, 0xad, 0x47, 0x19, 0x70,
0x5c, 0x06, 0xbd, 0x01, 0xe3, 0x2d, 0x43, 0xd3, 0xb8, 0x3f, 0x2e, 0x1a, 0x3d, 0x9d, 0x96, 0x47,
0x38, 0x0a, 0x62, 0xe7, 0x71, 0x31, 0x44, 0xc1, 0x11, 0x4e, 0x44, 0x00, 0x5a, 0x6e, 0xc2, 0xb1,
0xcb, 0xc0, 0xe3, 0xe3, 0xf5, 0xac, 0x31, 0xc0, 0x4b, 0x55, 0x7e, 0x0d, 0xe0, 0x0d, 0xd9, 0x38,
0x00, 0x2c, 0xff, 0x42, 0x82, 0xb9, 0x94, 0xd0, 0x81, 0xde, 0x0a, 0xa5, 0xd8, 0xbf, 0x8c, 0xa4,
0xd8, 0x0b, 0x29, 0x62, 0x81, 0x3c, 0xab, 0xc3, 0x98, 0xc5, 0x66, 0xa5, 0x77, 0x1c, 0x16, 0x11,
0x23, 0x6f, 0x0e, 0x98, 0x06, 0x0e, 0xca, 0xf8, 0x31, 0x7f, 0xea, 0xe8, 0xb0, 0x32, 0x16, 0xa2,
0xe1, 0x30, 0xbc, 0xfc, 0x3f, 0x39, 0x80, 0x25, 0x62, 0x6a, 0x46, 0xbf, 0x4b, 0xf4, 0xd3, 0xa8,
0xa1, 0x36, 0x42, 0x35, 0xd4, 0xb5, 0x41, 0xdb, 0xe3, 0x99, 0x96, 0x5a, 0x44, 0xfd, 0x6d, 0xa4,
0x88, 0xaa, 0x65, 0x87, 0x7c, 0x72, 0x15, 0xf5, 0xab, 0x3c, 0x4c, 0xfb, 0xcc, 0x7e, 0x19, 0x75,
0x27, 0xb4, 0xc7, 0x7f, 0x11, 0xd9, 0xe3, 0xb9, 0x04, 0x91, 0x67, 0x56, 0x47, 0x3d, 0xfd, 0x7a,
0x06, 0x3d, 0x84, 0x71, 0x56, 0x38, 0x39, 0xee, 0xc1, 0xcb, 0xb2, 0xe1, 0x63, 0x97, 0x65, 0x5e,
0x02, 0x5d, 0x0d, 0x21, 0xe1, 0x08, 0x72, 0x4a, 0x19, 0x58, 0x7c, 0xd6, 0x65, 0xa0, 0xfc, 0x85,
0x04, 0xe3, 0xfe, 0x36, 0x9d, 0x42, 0xd1, 0xb6, 0x1e, 0x2e, 0xda, 0x5e, 0xca, 0xec, 0xa2, 0x29,
0x55, 0xdb, 0xef, 0x58, 0x81, 0xef, 0x31, 0xb1, 0x03, 0xbe, 0xad, 0xb4, 0xf6, 0xd0, 0x25, 0x28,
0xe8, 0x4a, 0xd7, 0xf5, 0x4c, 0xef, 0xb0, 0xac, 0x2b, 0x5d, 0x82, 0x39, 0x05, 0x7d, 0x2a, 0x01,
0x12, 0x59, 0x60, 0x41, 0xd7, 0x0d, 0xaa, 0x38, 0xb1, 0xd2, 0x31, 0x6b, 0x25, 0xb3, 0x59, 0xae,
0xc6, 0xea, 0x56, 0x0c, 0xeb, 0xae, 0x4e, 0xad, 0xbe, 0xbf, 0x23, 0x71, 0x06, 0x9c, 0x60, 0x00,
0x52, 0x00, 0x2c, 0x81, 0xb9, 0x69, 0x88, 0x83, 0x7c, 0x2d, 0x43, 0xcc, 0x63, 0x02, 0x8b, 0x86,
0xbe, 0xa3, 0x76, 0xfc, 0xb0, 0x83, 0x3d, 0x20, 0x1c, 0x00, 0x3d, 0x7f, 0x17, 0xe6, 0x52, 0xac,
0x45, 0x93, 0x90, 0xdf, 0x23, 0x7d, 0x67, 0xd9, 0x30, 0xfb, 0x13, 0xcd, 0xc0, 0xd0, 0xbe, 0xa2,
0xf5, 0x9c, 0xf0, 0x3b, 0x82, 0x9d, 0x1f, 0x6f, 0xe4, 0x6e, 0x4b, 0xf2, 0xe7, 0x43, 0x41, 0xdf,
0xe1, 0x15, 0xf3, 0x15, 0xf6, 0xd1, 0x6a, 0x6a, 0x6a, 0x4b, 0xb1, 0x45, 0x21, 0x74, 0xd6, 0xf9,
0x60, 0x75, 0xc6, 0xb0, 0x47, 0x0d, 0xd5, 0xd6, 0xb9, 0x67, 0x5b, 0x5b, 0xe7, 0x9f, 0x4e, 0x6d,
0xfd, 0xf7, 0x50, 0xb2, 0xdd, 0xaa, 0xba, 0xc0, 0x21, 0xaf, 0x1f, 0x23, 0xbe, 0x8a, 0x82, 0xda,
0x53, 0xe0, 0x95, 0xd2, 0x1e, 0x68, 0x52, 0x11, 0x3d, 0x74, 0xcc, 0x22, 0xfa, 0xa9, 0x16, 0xbe,
0x2c, 0xa6, 0x9a, 0x4a, 0xcf, 0x26, 0x6d, 0x1e, 0x88, 0x4a, 0x7e, 0x4c, 0x6d, 0xf0, 0x51, 0x2c,
0xa8, 0xe8, 0x83, 0x90, 0xcb, 0x96, 0x4e, 0xe2, 0xb2, 0xe3, 0xe9, 0xee, 0x8a, 0xb6, 0x60, 0xce,
0xb4, 0x8c, 0x8e, 0x45, 0x6c, 0x7b, 0x89, 0x28, 0x6d, 0x4d, 0xd5, 0x89, 0xbb, 0x3e, 0x4e, 0x45,
0x74, 0xe1, 0xe8, 0xb0, 0x32, 0xd7, 0x48, 0x66, 0xc1, 0x69, 0xb2, 0xf2, 0xa3, 0x02, 0x4c, 0x46,
0x33, 0x60, 0x4a, 0x91, 0x2a, 0x9d, 0xa8, 0x48, 0xbd, 0x1a, 0x38, 0x0c, 0x4e, 0x05, 0x1f, 0xb8,
0xc1, 0x89, 0x1d, 0x88, 0x05, 0x98, 0x10, 0xd1, 0xc0, 0x25, 0x8a, 0x32, 0xdd, 0xdb, 0xfd, 0xad,
0x30, 0x19, 0x47, 0xf9, 0x59, 0xe9, 0xe9, 0x57, 0x94, 0x2e, 0x48, 0x21, 0x5c, 0x7a, 0x2e, 0x44,
0x19, 0x70, 0x5c, 0x06, 0xad, 0xc1, 0x74, 0x4f, 0x8f, 0x43, 0x39, 0xde, 0x78, 0x41, 0x40, 0x4d,
0x6f, 0xc5, 0x59, 0x70, 0x92, 0x1c, 0xda, 0x09, 0x55, 0xa3, 0xc3, 0x3c, 0xc2, 0xde, 0xc8, 0x7c,
0x76, 0x32, 0x97, 0xa3, 0xe8, 0x0e, 0x8c, 0x59, 0xfc, 0xbb, 0xc3, 0x35, 0xd8, 0xa9, 0xdd, 0xcf,
0x09, 0xb1, 0x31, 0x1c, 0x24, 0xe2, 0x30, 0x6f, 0x42, 0xb9, 0x5d, 0xca, 0x5a, 0x6e, 0xcb, 0x3f,
0x93, 0x82, 0x49, 0xc8, 0x2b, 0x81, 0x07, 0xdd, 0x32, 0xc5, 0x24, 0x02, 0xd5, 0x91, 0x91, 0x5c,
0xfd, 0xde, 0x3a, 0x56, 0xf5, 0xeb, 0x27, 0xcf, 0xc1, 0xe5, 0xef, 0x67, 0x12, 0xcc, 0x2e, 0x37,
0xef, 0x59, 0x46, 0xcf, 0x74, 0xcd, 0xd9, 0x30, 0x9d, 0x75, 0x7d, 0x1d, 0x0a, 0x56, 0x4f, 0x73,
0xe7, 0xf1, 0xa2, 0x3b, 0x0f, 0xdc, 0xd3, 0xd8, 0x3c, 0xa6, 0x23, 0x52, 0xce, 0x24, 0x98, 0x00,
0x5a, 0x87, 0x61, 0x4b, 0xd1, 0x3b, 0xc4, 0x4d, 0xab, 0x97, 0x07, 0x58, 0xbf, 0xb2, 0x84, 0x19,
0x7b, 0xa0, 0x78, 0xe3, 0xd2, 0x58, 0xa0, 0xc8, 0xff, 0x2e, 0xc1, 0xc4, 0xfd, 0xcd, 0xcd, 0xc6,
0x8a, 0xce, 0x4f, 0x34, 0xbf, 0x5b, 0xbd, 0x04, 0x05, 0x53, 0xa1, 0xbb, 0xd1, 0x4c, 0xcf, 0x68,
0x98, 0x53, 0xd0, 0x7b, 0x50, 0x64, 0x91, 0x84, 0xe8, 0xed, 0x8c, 0xa5, 0xb6, 0x80, 0xaf, 0x3b,
0x42, 0x7e, 0x85, 0x28, 0x06, 0xb0, 0x0b, 0x27, 0xef, 0xc1, 0x4c, 0xc0, 0x1c, 0xb6, 0x1e, 0x0f,
0x58, 0x76, 0x44, 0x4d, 0x18, 0x62, 0x9a, 0x59, 0x0e, 0xcc, 0x67, 0xb8, 0xcc, 0x8c, 0x4c, 0xc9,
0xaf, 0x74, 0xd8, 0x2f, 0x1b, 0x3b, 0x58, 0xf2, 0x1a, 0x8c, 0xf1, 0x0b, 0x65, 0xc3, 0xa2, 0x7c,
0x59, 0xd0, 0x45, 0xc8, 0x77, 0x55, 0x5d, 0xe4, 0xd9, 0x51, 0x21, 0x93, 0x67, 0x39, 0x82, 0x8d,
0x73, 0xb2, 0x72, 0x20, 0x22, 0x8f, 0x4f, 0x56, 0x0e, 0x30, 0x1b, 0x97, 0xef, 0x41, 0x51, 0x2c,
0x77, 0x10, 0x28, 0xff, 0x64, 0xa0, 0x7c, 0x02, 0xd0, 0x06, 0x14, 0x57, 0x1a, 0x75, 0xcd, 0x70,
0xaa, 0xae, 0x96, 0xda, 0xb6, 0xa2, 0x7b, 0xb1, 0xb8, 0xb2, 0x84, 0x31, 0xa7, 0x20, 0x19, 0x86,
0xc9, 0x41, 0x8b, 0x98, 0x94, 0x7b, 0xc4, 0x48, 0x1d, 0xd8, 0x2e, 0xdf, 0xe5, 0x23, 0x58, 0x50,
0xe4, 0xff, 0xc8, 0x41, 0x51, 0x2c, 0xc7, 0x29, 0x7c, 0x85, 0xad, 0x86, 0xbe, 0xc2, 0x5e, 0xce,
0xe6, 0x1a, 0xa9, 0x9f, 0x60, 0x9b, 0x91, 0x4f, 0xb0, 0xab, 0x19, 0xf1, 0x9e, 0xfc, 0xfd, 0xf5,
0x63, 0x09, 0xc6, 0xc3, 0x4e, 0x89, 0x6e, 0xc2, 0x28, 0x4b, 0x38, 0x6a, 0x8b, 0xac, 0xfb, 0x75,
0xae, 0x77, 0x09, 0xd3, 0xf4, 0x49, 0x38, 0xc8, 0x87, 0x3a, 0x9e, 0x18, 0xf3, 0x23, 0x31, 0xe9,
0xf4, 0x25, 0xed, 0x51, 0x55, 0xab, 0x3a, 0x8f, 0x24, 0xd5, 0x15, 0x9d, 0x6e, 0x58, 0x4d, 0x6a,
0xa9, 0x7a, 0x27, 0xa6, 0x88, 0x3b, 0x65, 0x10, 0x59, 0xfe, 0xa9, 0x04, 0xa3, 0xc2, 0xe4, 0x53,
0xf8, 0xaa, 0xf8, 0x9b, 0xf0, 0x57, 0xc5, 0xe5, 0x8c, 0x07, 0x3c, 0xf9, 0x93, 0xe2, 0xff, 0x7d,
0xd3, 0xd9, 0x91, 0x66, 0x5e, 0xbd, 0x6b, 0xd8, 0x34, 0xea, 0xd5, 0xec, 0x30, 0x62, 0x4e, 0x41,
0x3d, 0x98, 0x54, 0x23, 0x31, 0x40, 0x2c, 0x6d, 0x2d, 0x9b, 0x25, 0x9e, 0x58, 0xbd, 0x2c, 0xe0,
0x27, 0xa3, 0x14, 0x1c, 0x53, 0x21, 0x13, 0x88, 0x71, 0xa1, 0x77, 0xa1, 0xb0, 0x4b, 0xa9, 0x99,
0x70, 0x5f, 0x3d, 0x20, 0xf2, 0xf8, 0x26, 0x94, 0xf8, 0xec, 0x36, 0x37, 0x1b, 0x98, 0x43, 0xc9,
0xbf, 0xf7, 0xd7, 0xa3, 0xe9, 0xf8, 0xb8, 0x17, 0x4f, 0xa5, 0x93, 0xc4, 0xd3, 0xd1, 0xa4, 0x58,
0x8a, 0xee, 0x43, 0x9e, 0x6a, 0x59, 0x3f, 0x0b, 0x05, 0xe2, 0xe6, 0x6a, 0xd3, 0x0f, 0x48, 0x9b,
0xab, 0x4d, 0xcc, 0x20, 0xd0, 0x06, 0x0c, 0xb1, 0xec, 0xc3, 0x8e, 0x60, 0x3e, 0xfb, 0x91, 0x66,
0xf3, 0xf7, 0x1d, 0x82, 0xfd, 0xb2, 0xb1, 0x83, 0x23, 0x7f, 0x0c, 0x63, 0xa1, 0x73, 0x8a, 0x3e,
0x82, 0xb3, 0x9a, 0xa1, 0xb4, 0xeb, 0x8a, 0xa6, 0xe8, 0x2d, 0xe2, 0x3e, 0x0e, 0x5c, 0x4e, 0xfa,
0xc2, 0x58, 0x0d, 0xf0, 0x89, 0x53, 0x3e, 0x23, 0x94, 0x9c, 0x0d, 0xd2, 0x70, 0x08, 0x51, 0x56,
0x00, 0xfc, 0x39, 0xa2, 0x0a, 0x0c, 0x31, 0x3f, 0x73, 0xf2, 0xc9, 0x48, 0x7d, 0x84, 0x59, 0xc8,
0xdc, 0xcf, 0xc6, 0xce, 0x38, 0xba, 0x01, 0x60, 0x93, 0x96, 0x45, 0x28, 0x0f, 0x06, 0xb9, 0xf0,
0x03, 0x63, 0xd3, 0xa3, 0xe0, 0x00, 0x97, 0xfc, 0x73, 0x09, 0xc6, 0xd6, 0x09, 0xfd, 0xc4, 0xb0,
0xf6, 0x1a, 0x86, 0xa6, 0xb6, 0xfa, 0xa7, 0x10, 0x6c, 0x71, 0x28, 0xd8, 0xbe, 0x32, 0x60, 0x67,
0x42, 0xd6, 0xa5, 0x85, 0x5c, 0xf9, 0x0b, 0x09, 0xe6, 0x42, 0x9c, 0x77, 0xfd, 0xa3, 0xbb, 0x05,
0x43, 0xa6, 0x61, 0x51, 0x37, 0x11, 0x1f, 0x4b, 0x21, 0x0b, 0x63, 0x81, 0x54, 0xcc, 0x60, 0xb0,
0x83, 0x86, 0x56, 0x21, 0x47, 0x0d, 0xe1, 0xaa, 0xc7, 0xc3, 0x24, 0xc4, 0xaa, 0x83, 0xc0, 0xcc,
0x6d, 0x1a, 0x38, 0x47, 0x0d, 0xb6, 0x11, 0xe5, 0x10, 0x57, 0x30, 0xf8, 0x3c, 0xa3, 0x19, 0x60,
0x28, 0xec, 0x58, 0x46, 0xf7, 0xc4, 0x73, 0xf0, 0x36, 0x62, 0xd9, 0x32, 0xba, 0x98, 0x63, 0xc9,
0x5f, 0x4a, 0x30, 0x15, 0xe2, 0x3c, 0x85, 0xc0, 0xff, 0x6e, 0x38, 0xf0, 0x5f, 0x3d, 0xce, 0x44,
0x52, 0xc2, 0xff, 0x97, 0xb9, 0xc8, 0x34, 0xd8, 0x84, 0xd1, 0x0e, 0x8c, 0x9a, 0x46, 0xbb, 0xf9,
0x14, 0x9e, 0x03, 0x27, 0x58, 0xde, 0x6c, 0xf8, 0x58, 0x38, 0x08, 0x8c, 0x0e, 0x60, 0x4a, 0x57,
0xba, 0xc4, 0x36, 0x95, 0x16, 0x69, 0x3e, 0x85, 0x0b, 0x92, 0x73, 0xfc, 0xbd, 0x21, 0x8a, 0x88,
0xe3, 0x4a, 0xd0, 0x1a, 0x14, 0x55, 0x93, 0xd7, 0x71, 0xa2, 0x76, 0x19, 0x98, 0x45, 0x9d, 0xaa,
0xcf, 0x89, 0xe7, 0xe2, 0x07, 0x76, 0x31, 0xe4, 0x1f, 0x44, 0xbd, 0x81, 0xf9, 0x1f, 0xba, 0x07,
0x25, 0xde, 0x62, 0xd1, 0x32, 0x34, 0xf7, 0x65, 0x80, 0xed, 0x6c, 0x43, 0x8c, 0x3d, 0x3e, 0xac,
0x5c, 0x48, 0xb8, 0xf4, 0x75, 0xc9, 0xd8, 0x13, 0x46, 0xeb, 0x50, 0x30, 0xbf, 0x4f, 0x05, 0xc3,
0x93, 0x1c, 0x2f, 0x5b, 0x38, 0x8e, 0xfc, 0x4f, 0xf9, 0x88, 0xb9, 0x3c, 0xd5, 0x3d, 0x7c, 0x6a,
0xbb, 0xee, 0x55, 0x4c, 0xa9, 0x3b, 0xbf, 0x0d, 0x45, 0x91, 0xe1, 0x85, 0x33, 0xbf, 0x7e, 0x1c,
0x67, 0x0e, 0x66, 0x31, 0xef, 0x83, 0xc5, 0x1d, 0x74, 0x81, 0xd1, 0x87, 0x30, 0x4c, 0x1c, 0x15,
0x4e, 0x6e, 0xbc, 0x75, 0x1c, 0x15, 0x7e, 0x5c, 0xf5, 0x0b, 0x55, 0x31, 0x26, 0x50, 0xd1, 0x5b,
0x6c, 0xbd, 0x18, 0x2f, 0xfb, 0x08, 0xb4, 0xcb, 0x05, 0x9e, 0xae, 0x2e, 0x3a, 0xd3, 0xf6, 0x86,
0x1f, 0x1f, 0x56, 0xc0, 0xff, 0x89, 0x83, 0x12, 0xf2, 0x2f, 0x25, 0x98, 0xe2, 0x2b, 0xd4, 0xea,
0x59, 0x2a, 0xed, 0x9f, 0x5a, 0x62, 0x7a, 0x10, 0x4a, 0x4c, 0xaf, 0x0d, 0x58, 0x96, 0x98, 0x85,
0xa9, 0xc9, 0xe9, 0x2b, 0x09, 0xce, 0xc5, 0xb8, 0x4f, 0x21, 0x2e, 0x6e, 0x85, 0xe3, 0xe2, 0x2b,
0xc7, 0x9d, 0x50, 0x4a, 0x6c, 0xfc, 0xe7, 0xc9, 0x84, 0xe9, 0xf0, 0x93, 0x72, 0x03, 0xc0, 0xb4,
0xd4, 0x7d, 0x55, 0x23, 0x1d, 0xf1, 0x08, 0x5e, 0x0a, 0xb4, 0x38, 0x79, 0x14, 0x1c, 0xe0, 0x42,
0x36, 0xcc, 0xb6, 0xc9, 0x8e, 0xd2, 0xd3, 0xe8, 0x42, 0xbb, 0xbd, 0xa8, 0x98, 0xca, 0xb6, 0xaa,
0xa9, 0x54, 0x15, 0xd7, 0x05, 0x23, 0xf5, 0x3b, 0xce, 0xe3, 0x74, 0x12, 0xc7, 0xe3, 0xc3, 0xca,
0xc5, 0xa4, 0xd7, 0x21, 0x97, 0xa5, 0x8f, 0x53, 0xa0, 0x51, 0x1f, 0xca, 0x16, 0xf9, 0xb8, 0xa7,
0x5a, 0xa4, 0xbd, 0x64, 0x19, 0x66, 0x48, 0x6d, 0x9e, 0xab, 0xfd, 0xeb, 0xa3, 0xc3, 0x4a, 0x19,
0xa7, 0xf0, 0x0c, 0x56, 0x9c, 0x0a, 0x8f, 0x1e, 0xc2, 0xb4, 0xe2, 0x74, 0x86, 0x85, 0xb4, 0x3a,
0xa7, 0xe4, 0xf6, 0xd1, 0x61, 0x65, 0x7a, 0x21, 0x4e, 0x1e, 0xac, 0x30, 0x09, 0x14, 0xd5, 0xa0,
0xb8, 0xcf, 0xfb, 0xd6, 0xec, 0xf2, 0x10, 0xc7, 0x67, 0x89, 0xa0, 0xe8, 0xb4, 0xb2, 0x31, 0xcc,
0xe1, 0xe5, 0x26, 0x3f, 0x7d, 0x2e, 0x17, 0xfb, 0xa0, 0x64, 0xb5, 0xa4, 0x38, 0xf1, 0xfc, 0xc6,
0xb8, 0xe4, 0x47, 0xad, 0xfb, 0x3e, 0x09, 0x07, 0xf9, 0xd0, 0x07, 0x30, 0xb2, 0x2b, 0x6e, 0x25,
0xec, 0x72, 0x31, 0x53, 0x12, 0x0e, 0xdd, 0x62, 0xd4, 0xa7, 0x84, 0x8a, 0x11, 0x77, 0xd8, 0xc6,
0x3e, 0x22, 0x7a, 0x09, 0x8a, 0xfc, 0xc7, 0xca, 0x12, 0xbf, 0x8e, 0x2b, 0xf9, 0xb1, 0xed, 0xbe,
0x33, 0x8c, 0x5d, 0xba, 0xcb, 0xba, 0xd2, 0x58, 0xe4, 0xd7, 0xc2, 0x11, 0xd6, 0x95, 0xc6, 0x22,
0x76, 0xe9, 0xe8, 0x23, 0x28, 0xda, 0x64, 0x55, 0xd5, 0x7b, 0x07, 0x65, 0xc8, 0xf4, 0xa8, 0xdc,
0xbc, 0xcb, 0xb9, 0x23, 0x17, 0x63, 0xbe, 0x06, 0x41, 0xc7, 0x2e, 0x2c, 0xda, 0x85, 0x11, 0xab,
0xa7, 0x2f, 0xd8, 0x5b, 0x36, 0xb1, 0xca, 0xa3, 0x5c, 0xc7, 0xa0, 0x70, 0x8e, 0x5d, 0xfe, 0xa8,
0x16, 0x6f, 0x85, 0x3c, 0x0e, 0xec, 0x83, 0xa3, 0x7f, 0x93, 0x00, 0xd9, 0x3d, 0xd3, 0xd4, 0x48,
0x97, 0xe8, 0x54, 0xd1, 0xf8, 0x5d, 0x9c, 0x5d, 0x3e, 0xcb, 0x75, 0xbe, 0x3d, 0x68, 0x5e, 0x31,
0xc1, 0xa8, 0x72, 0xef, 0xd2, 0x3b, 0xce, 0x8a, 0x13, 0xf4, 0xb2, 0xa5, 0xdd, 0xb1, 0xf9, 0xdf,
0xe5, 0xb1, 0x4c, 0x4b, 0x9b, 0x7c, 0xe7, 0xe8, 0x2f, 0xad, 0xa0, 0x63, 0x17, 0x16, 0x3d, 0x80,
0x59, 0xb7, 0xed, 0x11, 0x1b, 0x06, 0x5d, 0x56, 0x35, 0x62, 0xf7, 0x6d, 0x4a, 0xba, 0xe5, 0x71,
0xbe, 0xed, 0x5e, 0xef, 0x07, 0x4e, 0xe4, 0xc2, 0x29, 0xd2, 0xa8, 0x0b, 0x15, 0x37, 0x64, 0xb0,
0xf3, 0xe4, 0xc5, 0xac, 0xbb, 0x76, 0x4b, 0xd1, 0x9c, 0x77, 0x80, 0x09, 0xae, 0xe0, 0xc5, 0xa3,
0xc3, 0x4a, 0x65, 0xe9, 0xc9, 0xac, 0x78, 0x10, 0x16, 0x7a, 0x0f, 0xca, 0x4a, 0x9a, 0x9e, 0x49,
0xae, 0xe7, 0x79, 0x16, 0x87, 0x52, 0x15, 0xa4, 0x4a, 0x23, 0x0a, 0x93, 0x4a, 0xb8, 0x01, 0xd5,
0x2e, 0x4f, 0x65, 0xba, 0x88, 0x8c, 0xf4, 0xad, 0xfa, 0x97, 0x11, 0x11, 0x82, 0x8d, 0x63, 0x1a,
0xd0, 0x3f, 0x00, 0x52, 0xa2, 0x3d, 0xb3, 0x76, 0x19, 0x65, 0x4a, 0x3f, 0xb1, 0x66, 0x5b, 0xdf,
0xed, 0x62, 0x24, 0x1b, 0x27, 0xe8, 0x41, 0xab, 0x30, 0x23, 0x46, 0xb7, 0x74, 0x5b, 0xd9, 0x21,
0xcd, 0xbe, 0xdd, 0xa2, 0x9a, 0x5d, 0x9e, 0xe6, 0xb1, 0x8f, 0x3f, 0x7c, 0x2d, 0x24, 0xd0, 0x71,
0xa2, 0x14, 0x7a, 0x1b, 0x26, 0x77, 0x0c, 0x6b, 0x5b, 0x6d, 0xb7, 0x89, 0xee, 0x22, 0xcd, 0x70,
0xa4, 0x19, 0xb6, 0x1a, 0xcb, 0x11, 0x1a, 0x8e, 0x71, 0x23, 0x1b, 0xce, 0x09, 0xe4, 0x86, 0x65,
0xb4, 0xd6, 0x8c, 0x9e, 0x4e, 0x9d, 0x92, 0xe8, 0x9c, 0x97, 0x62, 0xce, 0x2d, 0x24, 0x31, 0x3c,
0x3e, 0xac, 0x5c, 0x4a, 0xae, 0x80, 0x7d, 0x26, 0x9c, 0x8c, 0x8d, 0x76, 0x01, 0x78, 0x5c, 0x70,
0x8e, 0xdf, 0x2c, 0x3f, 0x7e, 0xb7, 0xb3, 0x44, 0x9d, 0xc4, 0x13, 0xe8, 0x3c, 0xc9, 0x79, 0x64,
0x1c, 0xc0, 0xe6, 0xbd, 0x32, 0xe2, 0xe5, 0xe4, 0x74, 0xfa, 0x8d, 0x8f, 0xd7, 0x2b, 0xe3, 0x9b,
0xf6, 0xd4, 0x7a, 0x65, 0x02, 0x90, 0x4f, 0xbe, 0xab, 0xfd, 0x6d, 0x0e, 0xa6, 0x7d, 0xe6, 0xcc,
0xbd, 0x32, 0x09, 0x22, 0x7f, 0xee, 0x39, 0x1e, 0xdc, 0x73, 0xfc, 0x85, 0x04, 0xe3, 0xfe, 0xd2,
0xfd, 0xf1, 0xf5, 0xaf, 0xf8, 0xb6, 0xa5, 0x54, 0xd4, 0x3f, 0xca, 0x05, 0x27, 0xf0, 0x27, 0xdf,
0x44, 0xf1, 0xfd, 0x1b, 0x85, 0xe5, 0xaf, 0xf2, 0x30, 0x19, 0x3d, 0x8d, 0xa1, 0xb7, 0x76, 0x69,
0xe0, 0x5b, 0x7b, 0x03, 0x66, 0x76, 0x7a, 0x9a, 0xd6, 0xe7, 0xcb, 0x10, 0x78, 0x70, 0x77, 0xde,
0xca, 0x9e, 0x17, 0x92, 0x33, 0xcb, 0x09, 0x3c, 0x38, 0x51, 0x32, 0xa5, 0x6f, 0x20, 0x7f, 0xa2,
0xbe, 0x81, 0xd8, 0x33, 0x76, 0xe1, 0x18, 0xcf, 0xd8, 0x89, 0x3d, 0x00, 0x43, 0x27, 0xe8, 0x01,
0x38, 0xc9, 0xa3, 0x7d, 0x42, 0x10, 0x1b, 0xd8, 0x43, 0xfa, 0x3c, 0x9c, 0x17, 0x62, 0x94, 0xbf,
0xa7, 0xeb, 0xd4, 0x32, 0x34, 0x8d, 0x58, 0x4b, 0xbd, 0x6e, 0xb7, 0x2f, 0xbf, 0x09, 0xe3, 0xe1,
0x4e, 0x11, 0x67, 0xa7, 0x9d, 0x66, 0x15, 0xf1, 0x62, 0x19, 0xd8, 0x69, 0x67, 0x1c, 0x7b, 0x1c,
0xf2, 0xbf, 0x48, 0x30, 0x9b, 0xdc, 0x11, 0x8a, 0x34, 0x18, 0xef, 0x2a, 0x07, 0xc1, 0x2e, 0x5d,
0xe9, 0x84, 0x77, 0x49, 0xbc, 0x45, 0x60, 0x2d, 0x84, 0x85, 0x23, 0xd8, 0xf2, 0x77, 0x12, 0xcc,
0xa5, 0x3c, 0xce, 0x9f, 0xae, 0x25, 0xe8, 0x7d, 0x28, 0x75, 0x95, 0x83, 0x66, 0xcf, 0xea, 0x90,
0x13, 0xdf, 0x9e, 0xf1, 0x88, 0xb1, 0x26, 0x50, 0xb0, 0x87, 0x27, 0xff, 0x9f, 0x04, 0xcf, 0xa5,
0x56, 0x14, 0xe8, 0x56, 0xa8, 0x8f, 0x40, 0x8e, 0xf4, 0x11, 0xa0, 0xb8, 0xe0, 0x33, 0x6a, 0x23,
0xf8, 0x4c, 0x82, 0x72, 0xda, 0xd7, 0x16, 0xba, 0x19, 0x32, 0xf2, 0x85, 0x88, 0x91, 0x53, 0x31,
0xb9, 0x67, 0x64, 0xe3, 0x0f, 0x25, 0x98, 0x4d, 0xfe, 0xea, 0x44, 0xaf, 0x86, 0x2c, 0xac, 0x44,
0x2c, 0x9c, 0x88, 0x48, 0x09, 0xfb, 0x3e, 0x84, 0x71, 0xf1, 0x6d, 0x2a, 0x60, 0xc4, 0xde, 0xcb,
0x49, 0x11, 0x5d, 0x40, 0xb8, 0x95, 0x20, 0xf7, 0xaa, 0xf0, 0x18, 0x8e, 0xa0, 0xc9, 0xff, 0x9a,
0x83, 0xa1, 0x66, 0x4b, 0xd1, 0xc8, 0x29, 0x14, 0x83, 0xef, 0x84, 0x8a, 0xc1, 0x41, 0xff, 0xf7,
0xc3, 0xad, 0x4a, 0xad, 0x03, 0x71, 0xa4, 0x0e, 0x7c, 0x39, 0x13, 0xda, 0x93, 0x4b, 0xc0, 0xbf,
0x82, 0x11, 0x4f, 0xe9, 0xf1, 0x32, 0x93, 0xfc, 0xbf, 0x39, 0x18, 0x0d, 0xa8, 0x38, 0x66, 0x5e,
0xdb, 0x09, 0xd5, 0x03, 0xf9, 0x0c, 0xe5, 0x7f, 0x40, 0x57, 0xd5, 0xad, 0x00, 0x9c, 0xbe, 0x55,
0xbf, 0x53, 0x31, 0x5e, 0x18, 0xbc, 0x09, 0xe3, 0x54, 0xb1, 0x3a, 0x84, 0x7a, 0x37, 0xe3, 0x79,
0xee, 0x8b, 0x5e, 0xb7, 0xf3, 0x66, 0x88, 0x8a, 0x23, 0xdc, 0xe7, 0xef, 0xc0, 0x58, 0x48, 0xd9,
0xb1, 0xda, 0x4e, 0x7f, 0x22, 0xc1, 0x0b, 0x03, 0xef, 0x2d, 0x50, 0x3d, 0x74, 0x48, 0xaa, 0x91,
0x43, 0x32, 0x9f, 0x0e, 0xf0, 0xec, 0xda, 0x97, 0xea, 0xd7, 0x1e, 0x7d, 0x3b, 0x7f, 0xe6, 0xeb,
0x6f, 0xe7, 0xcf, 0x7c, 0xf3, 0xed, 0xfc, 0x99, 0x7f, 0x3c, 0x9a, 0x97, 0x1e, 0x1d, 0xcd, 0x4b,
0x5f, 0x1f, 0xcd, 0x4b, 0xdf, 0x1c, 0xcd, 0x4b, 0xbf, 0x3e, 0x9a, 0x97, 0xfe, 0xf3, 0xbb, 0xf9,
0x33, 0xef, 0x17, 0x05, 0xdc, 0x1f, 0x02, 0x00, 0x00, 0xff, 0xff, 0x51, 0x7e, 0x9f, 0x62, 0x14,
0x3c, 0x00, 0x00,
0x6b, 0x68, 0x0e, 0x90, 0x43, 0x0e, 0x41, 0x80, 0x00, 0x09, 0x92, 0x8b, 0x93, 0x1c, 0x63, 0x04,
0xc8, 0x29, 0x41, 0x72, 0xcb, 0x1e, 0x0c, 0x03, 0x0b, 0x78, 0x01, 0x61, 0xe1, 0x05, 0x7c, 0x5b,
0x9f, 0x88, 0x35, 0x7d, 0x5a, 0xec, 0x3f, 0xb0, 0xd0, 0x61, 0x77, 0x51, 0xd5, 0xd5, 0xdf, 0xdd,
0x9a, 0x26, 0x2d, 0x11, 0x8b, 0xc5, 0xde, 0x38, 0xf5, 0xde, 0xfb, 0xbd, 0x57, 0x55, 0xaf, 0xde,
0x7b, 0x5d, 0xf5, 0x08, 0xcb, 0x7b, 0x77, 0xec, 0xaa, 0x6a, 0xd4, 0xf6, 0x7a, 0xdb, 0xc4, 0xd2,
0x09, 0x25, 0x76, 0x6d, 0x9f, 0xe8, 0x6d, 0xc3, 0xaa, 0x09, 0x82, 0x62, 0xaa, 0x35, 0x72, 0x40,
0x89, 0x6e, 0xab, 0x86, 0x6e, 0xd7, 0xf6, 0xaf, 0x6f, 0x13, 0xaa, 0x5c, 0xaf, 0x75, 0x88, 0x4e,
0x2c, 0x85, 0x92, 0x76, 0xd5, 0xb4, 0x0c, 0x6a, 0xa0, 0x8b, 0x0e, 0x7b, 0x55, 0x31, 0xd5, 0xaa,
0xcf, 0x5e, 0x15, 0xec, 0xe7, 0xaf, 0x75, 0x54, 0xba, 0xdb, 0xdb, 0xae, 0xb6, 0x8c, 0x6e, 0xad,
0x63, 0x74, 0x8c, 0x1a, 0x97, 0xda, 0xee, 0xed, 0xf0, 0x5f, 0xfc, 0x07, 0xff, 0xcb, 0x41, 0x3b,
0x2f, 0x07, 0x94, 0xb7, 0x0c, 0x8b, 0xd4, 0xf6, 0x63, 0x1a, 0xcf, 0xdf, 0xf4, 0x79, 0xba, 0x4a,
0x6b, 0x57, 0xd5, 0x89, 0xd5, 0xaf, 0x99, 0x7b, 0x1d, 0x36, 0x60, 0xd7, 0xba, 0x84, 0x2a, 0x49,
0x52, 0xb5, 0x34, 0x29, 0xab, 0xa7, 0x53, 0xb5, 0x4b, 0x62, 0x02, 0xb7, 0x07, 0x09, 0xd8, 0xad,
0x5d, 0xd2, 0x55, 0x62, 0x72, 0xaf, 0xa7, 0xc9, 0xf5, 0xa8, 0xaa, 0xd5, 0x54, 0x9d, 0xda, 0xd4,
0x8a, 0x0a, 0xc9, 0x37, 0x61, 0x72, 0x41, 0xd3, 0x8c, 0x4f, 0x49, 0x7b, 0xb1, 0xb9, 0xb2, 0x64,
0xa9, 0xfb, 0xc4, 0x42, 0x97, 0xa0, 0xa0, 0x2b, 0x5d, 0x52, 0x96, 0x2e, 0x49, 0x57, 0x46, 0xea,
0x67, 0x1f, 0x1f, 0x56, 0xce, 0x1c, 0x1d, 0x56, 0x0a, 0xeb, 0x4a, 0x97, 0x60, 0x4e, 0x91, 0xef,
0xc2, 0x94, 0x90, 0x5a, 0xd6, 0xc8, 0xc1, 0x43, 0x43, 0xeb, 0x75, 0x09, 0xba, 0x0c, 0xc3, 0x6d,
0x0e, 0x20, 0x04, 0xc7, 0x85, 0xe0, 0xb0, 0x03, 0x8b, 0x05, 0x55, 0xb6, 0x61, 0x42, 0x08, 0x3f,
0x30, 0x6c, 0xda, 0x50, 0xe8, 0x2e, 0xba, 0x01, 0x60, 0x2a, 0x74, 0xb7, 0x61, 0x91, 0x1d, 0xf5,
0x40, 0x88, 0x23, 0x21, 0x0e, 0x0d, 0x8f, 0x82, 0x03, 0x5c, 0xe8, 0x2a, 0x94, 0x2c, 0xa2, 0xb4,
0x37, 0x74, 0xad, 0x5f, 0xce, 0x5d, 0x92, 0xae, 0x94, 0xea, 0x93, 0x42, 0xa2, 0x84, 0xc5, 0x38,
0xf6, 0x38, 0xe4, 0xcf, 0x72, 0x30, 0xb2, 0xa4, 0x90, 0xae, 0xa1, 0x37, 0x09, 0x45, 0x1f, 0x43,
0x89, 0x6d, 0x57, 0x5b, 0xa1, 0x0a, 0xd7, 0x36, 0x7a, 0xe3, 0xb5, 0xaa, 0xef, 0x4e, 0xde, 0xea,
0x55, 0xcd, 0xbd, 0x0e, 0x1b, 0xb0, 0xab, 0x8c, 0xbb, 0xba, 0x7f, 0xbd, 0xba, 0xb1, 0xfd, 0x88,
0xb4, 0xe8, 0x1a, 0xa1, 0x8a, 0x6f, 0x9f, 0x3f, 0x86, 0x3d, 0x54, 0xb4, 0x0e, 0x05, 0xdb, 0x24,
0x2d, 0x6e, 0xd9, 0xe8, 0x8d, 0xab, 0xd5, 0xa7, 0x3a, 0x6b, 0xd5, 0xb3, 0xac, 0x69, 0x92, 0x96,
0xbf, 0xe2, 0xec, 0x17, 0xe6, 0x38, 0xe8, 0x21, 0x0c, 0xdb, 0x54, 0xa1, 0x3d, 0xbb, 0x9c, 0xe7,
0x88, 0xd5, 0xcc, 0x88, 0x5c, 0xca, 0xdf, 0x0c, 0xe7, 0x37, 0x16, 0x68, 0xf2, 0x2f, 0x73, 0x80,
0x3c, 0xde, 0x45, 0x43, 0x6f, 0xab, 0x54, 0x35, 0x74, 0xf4, 0x26, 0x14, 0x68, 0xdf, 0x74, 0x5d,
0xe0, 0xb2, 0x6b, 0xd0, 0x66, 0xdf, 0x24, 0x4f, 0x0e, 0x2b, 0xb3, 0x71, 0x09, 0x46, 0xc1, 0x5c,
0x06, 0xad, 0x7a, 0xa6, 0xe6, 0xb8, 0xf4, 0xcd, 0xb0, 0xea, 0x27, 0x87, 0x95, 0x84, 0xc3, 0x56,
0xf5, 0x90, 0xc2, 0x06, 0xa2, 0x7d, 0x40, 0x9a, 0x62, 0xd3, 0x4d, 0x4b, 0xd1, 0x6d, 0x47, 0x93,
0xda, 0x25, 0x62, 0x11, 0x5e, 0xcd, 0xb6, 0x69, 0x4c, 0xa2, 0x7e, 0x5e, 0x58, 0x81, 0x56, 0x63,
0x68, 0x38, 0x41, 0x03, 0xf3, 0x66, 0x8b, 0x28, 0xb6, 0xa1, 0x97, 0x0b, 0x61, 0x6f, 0xc6, 0x7c,
0x14, 0x0b, 0x2a, 0x7a, 0x05, 0x8a, 0x5d, 0x62, 0xdb, 0x4a, 0x87, 0x94, 0x87, 0x38, 0xe3, 0x84,
0x60, 0x2c, 0xae, 0x39, 0xc3, 0xd8, 0xa5, 0xcb, 0x5f, 0x48, 0x30, 0xe6, 0xad, 0xdc, 0xaa, 0x6a,
0x53, 0xf4, 0x57, 0x31, 0x3f, 0xac, 0x66, 0x9b, 0x12, 0x93, 0xe6, 0x5e, 0xe8, 0xf9, 0xbc, 0x3b,
0x12, 0xf0, 0xc1, 0x35, 0x18, 0x52, 0x29, 0xe9, 0xb2, 0x7d, 0xc8, 0x5f, 0x19, 0xbd, 0x71, 0x25,
0xab, 0xcb, 0xd4, 0xc7, 0x04, 0xe8, 0xd0, 0x0a, 0x13, 0xc7, 0x0e, 0x8a, 0xfc, 0xaf, 0x85, 0x80,
0xf9, 0xcc, 0x35, 0xd1, 0x87, 0x50, 0xb2, 0x89, 0x46, 0x5a, 0xd4, 0xb0, 0x84, 0xf9, 0xaf, 0x67,
0x34, 0x5f, 0xd9, 0x26, 0x5a, 0x53, 0x88, 0xd6, 0xcf, 0x32, 0xfb, 0xdd, 0x5f, 0xd8, 0x83, 0x44,
0xef, 0x41, 0x89, 0x92, 0xae, 0xa9, 0x29, 0x94, 0x88, 0x73, 0xf4, 0x72, 0x70, 0x0a, 0xcc, 0x73,
0x18, 0x58, 0xc3, 0x68, 0x6f, 0x0a, 0x36, 0x7e, 0x7c, 0xbc, 0x25, 0x71, 0x47, 0xb1, 0x07, 0x83,
0xf6, 0x61, 0xbc, 0x67, 0xb6, 0x19, 0x27, 0x65, 0x51, 0xb0, 0xd3, 0x17, 0x9e, 0x74, 0x3b, 0xeb,
0xda, 0x6c, 0x85, 0xa4, 0xeb, 0xb3, 0x42, 0xd7, 0x78, 0x78, 0x1c, 0x47, 0xb4, 0xa0, 0x05, 0x98,
0xe8, 0xaa, 0x3a, 0x8b, 0x4b, 0xfd, 0x26, 0x69, 0x19, 0x7a, 0xdb, 0xe6, 0x6e, 0x35, 0x54, 0x9f,
0x13, 0x00, 0x13, 0x6b, 0x61, 0x32, 0x8e, 0xf2, 0xa3, 0x77, 0x01, 0xb9, 0xd3, 0xb8, 0xef, 0x04,
0x71, 0xd5, 0xd0, 0xb9, 0xcf, 0xe5, 0x7d, 0xe7, 0xde, 0x8c, 0x71, 0xe0, 0x04, 0x29, 0xb4, 0x0a,
0x33, 0x16, 0xd9, 0x57, 0xd9, 0x1c, 0x1f, 0xa8, 0x36, 0x35, 0xac, 0xfe, 0xaa, 0xda, 0x55, 0x69,
0x79, 0x98, 0xdb, 0x54, 0x3e, 0x3a, 0xac, 0xcc, 0xe0, 0x04, 0x3a, 0x4e, 0x94, 0x92, 0xff, 0x6d,
0x18, 0x26, 0x22, 0xf1, 0x06, 0x3d, 0x84, 0xd9, 0x56, 0xcf, 0xb2, 0x88, 0x4e, 0xd7, 0x7b, 0xdd,
0x6d, 0x62, 0x35, 0x5b, 0xbb, 0xa4, 0xdd, 0xd3, 0x48, 0x9b, 0x3b, 0xca, 0x50, 0x7d, 0x5e, 0x58,
0x3c, 0xbb, 0x98, 0xc8, 0x85, 0x53, 0xa4, 0xd9, 0x2a, 0xe8, 0x7c, 0x68, 0x4d, 0xb5, 0x6d, 0x0f,
0x33, 0xc7, 0x31, 0xbd, 0x55, 0x58, 0x8f, 0x71, 0xe0, 0x04, 0x29, 0x66, 0x63, 0x9b, 0xd8, 0xaa,
0x45, 0xda, 0x51, 0x1b, 0xf3, 0x61, 0x1b, 0x97, 0x12, 0xb9, 0x70, 0x8a, 0x34, 0xba, 0x05, 0xa3,
0x8e, 0x36, 0xbe, 0x7f, 0x62, 0xa3, 0xa7, 0x05, 0xd8, 0xe8, 0xba, 0x4f, 0xc2, 0x41, 0x3e, 0x36,
0x35, 0x63, 0xdb, 0x26, 0xd6, 0x3e, 0x69, 0xa7, 0x6f, 0xf0, 0x46, 0x8c, 0x03, 0x27, 0x48, 0xb1,
0xa9, 0x39, 0x1e, 0x18, 0x9b, 0xda, 0x70, 0x78, 0x6a, 0x5b, 0x89, 0x5c, 0x38, 0x45, 0x9a, 0xf9,
0xb1, 0x63, 0xf2, 0xc2, 0xbe, 0xa2, 0x6a, 0xca, 0xb6, 0x46, 0xca, 0xc5, 0xb0, 0x1f, 0xaf, 0x87,
0xc9, 0x38, 0xca, 0x8f, 0xee, 0xc3, 0x94, 0x33, 0xb4, 0xa5, 0x2b, 0x1e, 0x48, 0x89, 0x83, 0xbc,
0x20, 0x40, 0xa6, 0xd6, 0xa3, 0x0c, 0x38, 0x2e, 0x83, 0xde, 0x84, 0xf1, 0x96, 0xa1, 0x69, 0xdc,
0x1f, 0x17, 0x8d, 0x9e, 0x4e, 0xcb, 0x23, 0x1c, 0x05, 0xb1, 0xf3, 0xb8, 0x18, 0xa2, 0xe0, 0x08,
0x27, 0x22, 0x00, 0x2d, 0x37, 0xe1, 0xd8, 0x65, 0xe0, 0xf1, 0xf1, 0x7a, 0xd6, 0x18, 0xe0, 0xa5,
0x2a, 0xbf, 0x06, 0xf0, 0x86, 0x6c, 0x1c, 0x00, 0x96, 0x7f, 0x2a, 0xc1, 0x5c, 0x4a, 0xe8, 0x40,
0x6f, 0x87, 0x52, 0xec, 0x9f, 0x46, 0x52, 0xec, 0x85, 0x14, 0xb1, 0x40, 0x9e, 0xd5, 0x61, 0xcc,
0x62, 0xb3, 0xd2, 0x3b, 0x0e, 0x8b, 0x88, 0x91, 0xb7, 0x06, 0x4c, 0x03, 0x07, 0x65, 0xfc, 0x98,
0x3f, 0x75, 0x74, 0x58, 0x19, 0x0b, 0xd1, 0x70, 0x18, 0x5e, 0xfe, 0xf7, 0x1c, 0xc0, 0x12, 0x31,
0x35, 0xa3, 0xdf, 0x25, 0xfa, 0x69, 0xd4, 0x50, 0x1b, 0xa1, 0x1a, 0xea, 0xda, 0xa0, 0xed, 0xf1,
0x4c, 0x4b, 0x2d, 0xa2, 0xfe, 0x32, 0x52, 0x44, 0xd5, 0xb2, 0x43, 0x3e, 0xbd, 0x8a, 0xfa, 0x79,
0x1e, 0xa6, 0x7d, 0x66, 0xbf, 0x8c, 0xba, 0x1b, 0xda, 0xe3, 0x3f, 0x89, 0xec, 0xf1, 0x5c, 0x82,
0xc8, 0x73, 0xab, 0xa3, 0x9e, 0x7d, 0x3d, 0x83, 0x1e, 0xc1, 0x38, 0x2b, 0x9c, 0x1c, 0xf7, 0xe0,
0x65, 0xd9, 0xf0, 0xb1, 0xcb, 0x32, 0x2f, 0x81, 0xae, 0x86, 0x90, 0x70, 0x04, 0x39, 0xa5, 0x0c,
0x2c, 0x3e, 0xef, 0x32, 0x50, 0xfe, 0x52, 0x82, 0x71, 0x7f, 0x9b, 0x4e, 0xa1, 0x68, 0x5b, 0x0f,
0x17, 0x6d, 0xaf, 0x64, 0x76, 0xd1, 0x94, 0xaa, 0xed, 0xd7, 0xac, 0xc0, 0xf7, 0x98, 0xd8, 0x01,
0xdf, 0x56, 0x5a, 0x7b, 0x83, 0xbf, 0xf1, 0xd0, 0x67, 0x12, 0x20, 0x91, 0x05, 0x16, 0x74, 0xdd,
0xa0, 0x8a, 0x13, 0x2b, 0x1d, 0xb3, 0x56, 0x32, 0x9b, 0xe5, 0x6a, 0xac, 0x6e, 0xc5, 0xb0, 0xee,
0xe9, 0xd4, 0xea, 0xfb, 0x3b, 0x12, 0x67, 0xc0, 0x09, 0x06, 0x20, 0x05, 0xc0, 0x12, 0x98, 0x9b,
0x86, 0x38, 0xc8, 0xd7, 0x32, 0xc4, 0x3c, 0x26, 0xb0, 0x68, 0xe8, 0x3b, 0x6a, 0xc7, 0x0f, 0x3b,
0xd8, 0x03, 0xc2, 0x01, 0xd0, 0xf3, 0xf7, 0x60, 0x2e, 0xc5, 0x5a, 0x34, 0x09, 0xf9, 0x3d, 0xd2,
0x77, 0x96, 0x0d, 0xb3, 0x3f, 0xd1, 0x0c, 0x0c, 0xed, 0x2b, 0x5a, 0xcf, 0x09, 0xbf, 0x23, 0xd8,
0xf9, 0xf1, 0x66, 0xee, 0x8e, 0x24, 0x7f, 0x31, 0x14, 0xf4, 0x1d, 0x5e, 0x31, 0x5f, 0x61, 0x1f,
0xad, 0xa6, 0xa6, 0xb6, 0x14, 0x5b, 0x14, 0x42, 0x67, 0x9d, 0x0f, 0x56, 0x67, 0x0c, 0x7b, 0xd4,
0x50, 0x6d, 0x9d, 0x7b, 0xbe, 0xb5, 0x75, 0xfe, 0xd9, 0xd4, 0xd6, 0x7f, 0x0d, 0x25, 0xdb, 0xad,
0xaa, 0x0b, 0x1c, 0xf2, 0xfa, 0x31, 0xe2, 0xab, 0x28, 0xa8, 0x3d, 0x05, 0x5e, 0x29, 0xed, 0x81,
0x26, 0x15, 0xd1, 0x43, 0xc7, 0x2c, 0xa2, 0x9f, 0x69, 0xe1, 0xcb, 0x62, 0xaa, 0xa9, 0xf4, 0x6c,
0xd2, 0xe6, 0x81, 0xa8, 0xe4, 0xc7, 0xd4, 0x06, 0x1f, 0xc5, 0x82, 0x8a, 0x3e, 0x0c, 0xb9, 0x6c,
0xe9, 0x24, 0x2e, 0x3b, 0x9e, 0xee, 0xae, 0x68, 0x0b, 0xe6, 0x4c, 0xcb, 0xe8, 0x58, 0xc4, 0xb6,
0x97, 0x88, 0xd2, 0xd6, 0x54, 0x9d, 0xb8, 0xeb, 0xe3, 0x54, 0x44, 0x17, 0x8e, 0x0e, 0x2b, 0x73,
0x8d, 0x64, 0x16, 0x9c, 0x26, 0x2b, 0x3f, 0x2e, 0xc0, 0x64, 0x34, 0x03, 0xa6, 0x14, 0xa9, 0xd2,
0x89, 0x8a, 0xd4, 0xab, 0x81, 0xc3, 0xe0, 0x54, 0xf0, 0x81, 0x1b, 0x9c, 0xd8, 0x81, 0x58, 0x80,
0x09, 0x11, 0x0d, 0x5c, 0xa2, 0x28, 0xd3, 0xbd, 0xdd, 0xdf, 0x0a, 0x93, 0x71, 0x94, 0x9f, 0x95,
0x9e, 0x7e, 0x45, 0xe9, 0x82, 0x14, 0xc2, 0xa5, 0xe7, 0x42, 0x94, 0x01, 0xc7, 0x65, 0xd0, 0x1a,
0x4c, 0xf7, 0xf4, 0x38, 0x94, 0xe3, 0x8d, 0x17, 0x04, 0xd4, 0xf4, 0x56, 0x9c, 0x05, 0x27, 0xc9,
0xa1, 0x9d, 0x50, 0x35, 0x3a, 0xcc, 0x23, 0xec, 0x8d, 0xcc, 0x67, 0x27, 0x73, 0x39, 0x8a, 0xee,
0xc2, 0x98, 0xc5, 0xbf, 0x3b, 0x5c, 0x83, 0x9d, 0xda, 0xfd, 0x9c, 0x10, 0x1b, 0xc3, 0x41, 0x22,
0x0e, 0xf3, 0x26, 0x94, 0xdb, 0xa5, 0xac, 0xe5, 0xb6, 0xfc, 0x63, 0x29, 0x98, 0x84, 0xbc, 0x12,
0x78, 0xd0, 0x2d, 0x53, 0x4c, 0x22, 0x50, 0x1d, 0x19, 0xc9, 0xd5, 0xef, 0xed, 0x63, 0x55, 0xbf,
0x7e, 0xf2, 0x1c, 0x5c, 0xfe, 0x7e, 0x2e, 0xc1, 0xec, 0x72, 0xf3, 0xbe, 0x65, 0xf4, 0x4c, 0xd7,
0x9c, 0x0d, 0xd3, 0x59, 0xd7, 0x37, 0xa0, 0x60, 0xf5, 0x34, 0x77, 0x1e, 0x2f, 0xbb, 0xf3, 0xc0,
0x3d, 0x8d, 0xcd, 0x63, 0x3a, 0x22, 0xe5, 0x4c, 0x82, 0x09, 0xa0, 0x75, 0x18, 0xb6, 0x14, 0xbd,
0x43, 0xdc, 0xb4, 0x7a, 0x79, 0x80, 0xf5, 0x2b, 0x4b, 0x98, 0xb1, 0x07, 0x8a, 0x37, 0x2e, 0x8d,
0x05, 0x8a, 0xfc, 0x4f, 0x12, 0x4c, 0x3c, 0xd8, 0xdc, 0x6c, 0xac, 0xe8, 0xfc, 0x44, 0xf3, 0xbb,
0xd5, 0x4b, 0x50, 0x30, 0x15, 0xba, 0x1b, 0xcd, 0xf4, 0x8c, 0x86, 0x39, 0x05, 0xbd, 0x0f, 0x45,
0x16, 0x49, 0x88, 0xde, 0xce, 0x58, 0x6a, 0x0b, 0xf8, 0xba, 0x23, 0xe4, 0x57, 0x88, 0x62, 0x00,
0xbb, 0x70, 0xf2, 0x1e, 0xcc, 0x04, 0xcc, 0x61, 0xeb, 0xf1, 0x90, 0x65, 0x47, 0xd4, 0x84, 0x21,
0xa6, 0x99, 0xe5, 0xc0, 0x7c, 0x86, 0xcb, 0xcc, 0xc8, 0x94, 0xfc, 0x4a, 0x87, 0xfd, 0xb2, 0xb1,
0x83, 0x25, 0xaf, 0xc1, 0x18, 0xbf, 0x50, 0x36, 0x2c, 0xca, 0x97, 0x05, 0x5d, 0x84, 0x7c, 0x57,
0xd5, 0x45, 0x9e, 0x1d, 0x15, 0x32, 0x79, 0x96, 0x23, 0xd8, 0x38, 0x27, 0x2b, 0x07, 0x22, 0xf2,
0xf8, 0x64, 0xe5, 0x00, 0xb3, 0x71, 0xf9, 0x3e, 0x14, 0xc5, 0x72, 0x07, 0x81, 0xf2, 0x4f, 0x07,
0xca, 0x27, 0x00, 0x6d, 0x40, 0x71, 0xa5, 0x51, 0xd7, 0x0c, 0xa7, 0xea, 0x6a, 0xa9, 0x6d, 0x2b,
0xba, 0x17, 0x8b, 0x2b, 0x4b, 0x18, 0x73, 0x0a, 0x92, 0x61, 0x98, 0x1c, 0xb4, 0x88, 0x49, 0xb9,
0x47, 0x8c, 0xd4, 0x81, 0xed, 0xf2, 0x3d, 0x3e, 0x82, 0x05, 0x45, 0xfe, 0xe7, 0x1c, 0x14, 0xc5,
0x72, 0x9c, 0xc2, 0x57, 0xd8, 0x6a, 0xe8, 0x2b, 0xec, 0xd5, 0x6c, 0xae, 0x91, 0xfa, 0x09, 0xb6,
0x19, 0xf9, 0x04, 0xbb, 0x9a, 0x11, 0xef, 0xe9, 0xdf, 0x5f, 0xff, 0x27, 0xc1, 0x78, 0xd8, 0x29,
0xd1, 0x2d, 0x18, 0x65, 0x09, 0x47, 0x6d, 0x91, 0x75, 0xbf, 0xce, 0xf5, 0x2e, 0x61, 0x9a, 0x3e,
0x09, 0x07, 0xf9, 0x50, 0xc7, 0x13, 0x63, 0x7e, 0x24, 0x26, 0x9d, 0xbe, 0xa4, 0x3d, 0xaa, 0x6a,
0x55, 0xe7, 0x69, 0xa5, 0xba, 0xa2, 0xd3, 0x0d, 0xab, 0x49, 0x2d, 0x55, 0xef, 0xc4, 0x14, 0x71,
0xa7, 0x0c, 0x22, 0xcb, 0x3f, 0x92, 0x60, 0x54, 0x98, 0x7c, 0x0a, 0x5f, 0x15, 0x7f, 0x11, 0xfe,
0xaa, 0xb8, 0x9c, 0xf1, 0x80, 0x27, 0x7f, 0x52, 0xfc, 0x97, 0x6f, 0x3a, 0x3b, 0xd2, 0xcc, 0xab,
0x77, 0x0d, 0x9b, 0x46, 0xbd, 0x9a, 0x1d, 0x46, 0xcc, 0x29, 0xa8, 0x07, 0x93, 0x6a, 0x24, 0x06,
0x88, 0xa5, 0xad, 0x65, 0xb3, 0xc4, 0x13, 0xab, 0x97, 0x05, 0xfc, 0x64, 0x94, 0x82, 0x63, 0x2a,
0x64, 0x02, 0x31, 0x2e, 0xf4, 0x1e, 0x14, 0x76, 0x29, 0x35, 0x13, 0xee, 0xab, 0x07, 0x44, 0x1e,
0xdf, 0x84, 0x12, 0x9f, 0xdd, 0xe6, 0x66, 0x03, 0x73, 0x28, 0xf9, 0x37, 0xfe, 0x7a, 0x34, 0x1d,
0x1f, 0xf7, 0xe2, 0xa9, 0x74, 0x92, 0x78, 0x3a, 0x9a, 0x14, 0x4b, 0xd1, 0x03, 0xc8, 0x53, 0x2d,
0xeb, 0x67, 0xa1, 0x40, 0xdc, 0x5c, 0x6d, 0xfa, 0x01, 0x69, 0x73, 0xb5, 0x89, 0x19, 0x04, 0xda,
0x80, 0x21, 0x96, 0x7d, 0xd8, 0x11, 0xcc, 0x67, 0x3f, 0xd2, 0x6c, 0xfe, 0xbe, 0x43, 0xb0, 0x5f,
0x36, 0x76, 0x70, 0xe4, 0x4f, 0x60, 0x2c, 0x74, 0x4e, 0xd1, 0xc7, 0x70, 0x56, 0x33, 0x94, 0x76,
0x5d, 0xd1, 0x14, 0xbd, 0x45, 0xdc, 0xc7, 0x81, 0xcb, 0x49, 0x5f, 0x18, 0xab, 0x01, 0x3e, 0x71,
0xca, 0x67, 0x84, 0x92, 0xb3, 0x41, 0x1a, 0x0e, 0x21, 0xca, 0x0a, 0x80, 0x3f, 0x47, 0x54, 0x81,
0x21, 0xe6, 0x67, 0x4e, 0x3e, 0x19, 0xa9, 0x8f, 0x30, 0x0b, 0x99, 0xfb, 0xd9, 0xd8, 0x19, 0x47,
0x37, 0x00, 0x6c, 0xd2, 0xb2, 0x08, 0xe5, 0xc1, 0x20, 0x17, 0x7e, 0x60, 0x6c, 0x7a, 0x14, 0x1c,
0xe0, 0x92, 0x7f, 0x22, 0xc1, 0xd8, 0x3a, 0xa1, 0x9f, 0x1a, 0xd6, 0x5e, 0xc3, 0xd0, 0xd4, 0x56,
0xff, 0x14, 0x82, 0x2d, 0x0e, 0x05, 0xdb, 0xd7, 0x06, 0xec, 0x4c, 0xc8, 0xba, 0xb4, 0x90, 0x2b,
0x7f, 0x29, 0xc1, 0x5c, 0x88, 0xf3, 0x9e, 0x7f, 0x74, 0xb7, 0x60, 0xc8, 0x34, 0x2c, 0xea, 0x26,
0xe2, 0x63, 0x29, 0x64, 0x61, 0x2c, 0x90, 0x8a, 0x19, 0x0c, 0x76, 0xd0, 0xd0, 0x2a, 0xe4, 0xa8,
0x21, 0x5c, 0xf5, 0x78, 0x98, 0x84, 0x58, 0x75, 0x10, 0x98, 0xb9, 0x4d, 0x03, 0xe7, 0xa8, 0xc1,
0x36, 0xa2, 0x1c, 0xe2, 0x0a, 0x06, 0x9f, 0xe7, 0x34, 0x03, 0x0c, 0x85, 0x1d, 0xcb, 0xe8, 0x9e,
0x78, 0x0e, 0xde, 0x46, 0x2c, 0x5b, 0x46, 0x17, 0x73, 0x2c, 0xf9, 0x2b, 0x09, 0xa6, 0x42, 0x9c,
0xa7, 0x10, 0xf8, 0xdf, 0x0b, 0x07, 0xfe, 0xab, 0xc7, 0x99, 0x48, 0x4a, 0xf8, 0xff, 0x2a, 0x17,
0x99, 0x06, 0x9b, 0x30, 0xda, 0x81, 0x51, 0xd3, 0x68, 0x37, 0x9f, 0xc1, 0x73, 0xe0, 0x04, 0xcb,
0x9b, 0x0d, 0x1f, 0x0b, 0x07, 0x81, 0xd1, 0x01, 0x4c, 0xe9, 0x4a, 0x97, 0xd8, 0xa6, 0xd2, 0x22,
0xcd, 0x67, 0x70, 0x41, 0x72, 0x8e, 0xbf, 0x37, 0x44, 0x11, 0x71, 0x5c, 0x09, 0x5a, 0x83, 0xa2,
0x6a, 0xf2, 0x3a, 0x4e, 0xd4, 0x2e, 0x03, 0xb3, 0xa8, 0x53, 0xf5, 0x39, 0xf1, 0x5c, 0xfc, 0xc0,
0x2e, 0x86, 0xfc, 0xdf, 0x51, 0x6f, 0x60, 0xfe, 0x87, 0xee, 0x43, 0x89, 0x37, 0x66, 0xb4, 0x0c,
0xcd, 0x7d, 0x19, 0x60, 0x3b, 0xdb, 0x10, 0x63, 0x4f, 0x0e, 0x2b, 0x17, 0x12, 0x2e, 0x7d, 0x5d,
0x32, 0xf6, 0x84, 0xd1, 0x3a, 0x14, 0xcc, 0x1f, 0x52, 0xc1, 0xf0, 0x24, 0xc7, 0xcb, 0x16, 0x8e,
0x23, 0xff, 0x5d, 0x3e, 0x62, 0x2e, 0x4f, 0x75, 0x8f, 0x9e, 0xd9, 0xae, 0x7b, 0x15, 0x53, 0xea,
0xce, 0x6f, 0x43, 0x51, 0x64, 0x78, 0xe1, 0xcc, 0x6f, 0x1c, 0xc7, 0x99, 0x83, 0x59, 0xcc, 0xfb,
0x60, 0x71, 0x07, 0x5d, 0x60, 0xf4, 0x11, 0x0c, 0x13, 0x47, 0x85, 0x93, 0x1b, 0x6f, 0x1f, 0x47,
0x85, 0x1f, 0x57, 0xfd, 0x42, 0x55, 0x8c, 0x09, 0x54, 0xf4, 0x36, 0x5b, 0x2f, 0xc6, 0xcb, 0x3e,
0x02, 0xed, 0x72, 0x81, 0xa7, 0xab, 0x8b, 0xce, 0xb4, 0xbd, 0xe1, 0x27, 0x87, 0x15, 0xf0, 0x7f,
0xe2, 0xa0, 0x84, 0xfc, 0x33, 0x09, 0xa6, 0xf8, 0x0a, 0xb5, 0x7a, 0x96, 0x4a, 0xfb, 0xa7, 0x96,
0x98, 0x1e, 0x86, 0x12, 0xd3, 0xcd, 0x01, 0xcb, 0x12, 0xb3, 0x30, 0x35, 0x39, 0x7d, 0x2d, 0xc1,
0xb9, 0x18, 0xf7, 0x29, 0xc4, 0xc5, 0xad, 0x70, 0x5c, 0x7c, 0xed, 0xb8, 0x13, 0x4a, 0x89, 0x8d,
0xbf, 0x9d, 0x4c, 0x98, 0x0e, 0x3f, 0x29, 0x37, 0x00, 0x4c, 0x4b, 0xdd, 0x57, 0x35, 0xd2, 0x11,
0x8f, 0xe0, 0xa5, 0x40, 0x8b, 0x93, 0x47, 0xc1, 0x01, 0x2e, 0x64, 0xc3, 0x6c, 0x9b, 0xec, 0x28,
0x3d, 0x8d, 0x2e, 0xb4, 0xdb, 0x8b, 0x8a, 0xa9, 0x6c, 0xab, 0x9a, 0x4a, 0x55, 0x71, 0x5d, 0x30,
0x52, 0xbf, 0xeb, 0x3c, 0x4e, 0x27, 0x71, 0x3c, 0x39, 0xac, 0x5c, 0x4c, 0x7a, 0x1d, 0x72, 0x59,
0xfa, 0x38, 0x05, 0x1a, 0xf5, 0xa1, 0x6c, 0x91, 0x4f, 0x7a, 0xaa, 0x45, 0xda, 0x4b, 0x96, 0x61,
0x86, 0xd4, 0xe6, 0xb9, 0xda, 0x3f, 0x3f, 0x3a, 0xac, 0x94, 0x71, 0x0a, 0xcf, 0x60, 0xc5, 0xa9,
0xf0, 0xe8, 0x11, 0x4c, 0x2b, 0xa2, 0x19, 0x2d, 0xa8, 0xd5, 0x39, 0x25, 0x77, 0x8e, 0x0e, 0x2b,
0xd3, 0x0b, 0x71, 0xf2, 0x60, 0x85, 0x49, 0xa0, 0xa8, 0x06, 0xc5, 0x7d, 0xde, 0xb7, 0x66, 0x97,
0x87, 0x38, 0x3e, 0x4b, 0x04, 0x45, 0xa7, 0x95, 0x8d, 0x61, 0x0e, 0x2f, 0x37, 0xf9, 0xe9, 0x73,
0xb9, 0xd8, 0x07, 0x25, 0xab, 0x25, 0xc5, 0x89, 0xe7, 0x37, 0xc6, 0x25, 0x3f, 0x6a, 0x3d, 0xf0,
0x49, 0x38, 0xc8, 0x87, 0x3e, 0x84, 0x91, 0x5d, 0x71, 0x2b, 0x61, 0x97, 0x8b, 0x99, 0x92, 0x70,
0xe8, 0x16, 0xa3, 0x3e, 0x25, 0x54, 0x8c, 0xb8, 0xc3, 0x36, 0xf6, 0x11, 0xd1, 0x2b, 0x50, 0xe4,
0x3f, 0x56, 0x96, 0xf8, 0x75, 0x5c, 0xc9, 0x8f, 0x6d, 0x0f, 0x9c, 0x61, 0xec, 0xd2, 0x5d, 0xd6,
0x95, 0xc6, 0x22, 0xbf, 0x16, 0x8e, 0xb0, 0xae, 0x34, 0x16, 0xb1, 0x4b, 0x47, 0x1f, 0x43, 0xd1,
0x26, 0xab, 0xaa, 0xde, 0x3b, 0x28, 0x43, 0xa6, 0x47, 0xe5, 0xe6, 0x3d, 0xce, 0x1d, 0xb9, 0x18,
0xf3, 0x35, 0x08, 0x3a, 0x76, 0x61, 0xd1, 0x2e, 0x8c, 0x58, 0x3d, 0x7d, 0xc1, 0xde, 0xb2, 0x89,
0x55, 0x1e, 0xe5, 0x3a, 0x06, 0x85, 0x73, 0xec, 0xf2, 0x47, 0xb5, 0x78, 0x2b, 0xe4, 0x71, 0x60,
0x1f, 0x1c, 0xfd, 0xa3, 0x04, 0xc8, 0xee, 0x99, 0xa6, 0x46, 0xba, 0x44, 0xa7, 0x8a, 0xc6, 0xef,
0xe2, 0xec, 0xf2, 0x59, 0xae, 0xf3, 0x9d, 0x41, 0xf3, 0x8a, 0x09, 0x46, 0x95, 0x7b, 0x97, 0xde,
0x71, 0x56, 0x9c, 0xa0, 0x97, 0x2d, 0xed, 0x8e, 0xcd, 0xff, 0x2e, 0x8f, 0x65, 0x5a, 0xda, 0xe4,
0x3b, 0x47, 0x7f, 0x69, 0x05, 0x1d, 0xbb, 0xb0, 0xe8, 0x21, 0xcc, 0xba, 0x6d, 0x8f, 0xd8, 0x30,
0xe8, 0xb2, 0xaa, 0x11, 0xbb, 0x6f, 0x53, 0xd2, 0x2d, 0x8f, 0xf3, 0x6d, 0xf7, 0x7a, 0x3f, 0x70,
0x22, 0x17, 0x4e, 0x91, 0x46, 0x5d, 0xa8, 0xb8, 0x21, 0x83, 0x9d, 0x27, 0x2f, 0x66, 0xdd, 0xb3,
0x5b, 0x8a, 0xe6, 0xbc, 0x03, 0x4c, 0x70, 0x05, 0x2f, 0x1f, 0x1d, 0x56, 0x2a, 0x4b, 0x4f, 0x67,
0xc5, 0x83, 0xb0, 0xd0, 0xfb, 0x50, 0x56, 0xd2, 0xf4, 0x4c, 0x72, 0x3d, 0x2f, 0xb2, 0x38, 0x94,
0xaa, 0x20, 0x55, 0x1a, 0x51, 0x98, 0x54, 0xc2, 0x0d, 0xa8, 0x76, 0x79, 0x2a, 0xd3, 0x45, 0x64,
0xa4, 0x6f, 0xd5, 0xbf, 0x8c, 0x88, 0x10, 0x6c, 0x1c, 0xd3, 0x80, 0xfe, 0x06, 0x90, 0x12, 0xed,
0x99, 0xb5, 0xcb, 0x28, 0x53, 0xfa, 0x89, 0x35, 0xdb, 0xfa, 0x6e, 0x17, 0x23, 0xd9, 0x38, 0x41,
0x0f, 0x5a, 0x85, 0x19, 0x31, 0xba, 0xa5, 0xdb, 0xca, 0x0e, 0x69, 0xf6, 0xed, 0x16, 0xd5, 0xec,
0xf2, 0x34, 0x8f, 0x7d, 0xfc, 0xe1, 0x6b, 0x21, 0x81, 0x8e, 0x13, 0xa5, 0xd0, 0x3b, 0x30, 0xb9,
0x63, 0x58, 0xdb, 0x6a, 0xbb, 0x4d, 0x74, 0x17, 0x69, 0x86, 0x23, 0xcd, 0xb0, 0xd5, 0x58, 0x8e,
0xd0, 0x70, 0x8c, 0x1b, 0xd9, 0x70, 0x4e, 0x20, 0x37, 0x2c, 0xa3, 0xb5, 0x66, 0xf4, 0x74, 0xea,
0x94, 0x44, 0xe7, 0xbc, 0x14, 0x73, 0x6e, 0x21, 0x89, 0xe1, 0xc9, 0x61, 0xe5, 0x52, 0x72, 0x05,
0xec, 0x33, 0xe1, 0x64, 0x6c, 0xb4, 0x0b, 0xc0, 0xe3, 0x82, 0x73, 0xfc, 0x66, 0xf9, 0xf1, 0xbb,
0x93, 0x25, 0xea, 0x24, 0x9e, 0x40, 0xe7, 0x49, 0xce, 0x23, 0xe3, 0x00, 0x36, 0xfb, 0x4a, 0x51,
0x22, 0x6d, 0xd5, 0x76, 0x79, 0x8e, 0xef, 0x75, 0x2d, 0xdb, 0x5e, 0x7b, 0x72, 0x81, 0xa7, 0xa9,
0x28, 0x22, 0x8e, 0x2b, 0xe1, 0x5d, 0x3a, 0xe2, 0xcd, 0xe6, 0x74, 0x3a, 0x9d, 0x8f, 0xd7, 0xa5,
0xe3, 0x9b, 0xf6, 0xcc, 0xba, 0x74, 0x02, 0x90, 0x4f, 0xbf, 0x25, 0xfe, 0x55, 0x0e, 0xa6, 0x7d,
0xe6, 0xcc, 0x5d, 0x3a, 0x09, 0x22, 0x7f, 0xec, 0x76, 0x1e, 0xdc, 0xed, 0xfc, 0xa5, 0x04, 0xe3,
0xfe, 0xd2, 0xfd, 0xfe, 0x75, 0xce, 0xf8, 0xb6, 0xa5, 0xd4, 0xf2, 0xff, 0x9b, 0x0b, 0x4e, 0xe0,
0x0f, 0xbe, 0x7d, 0xe3, 0x87, 0xb7, 0x28, 0xcb, 0x5f, 0xe7, 0x61, 0x32, 0x7a, 0x1a, 0x43, 0xaf,
0xfc, 0xd2, 0xc0, 0x57, 0xfe, 0x06, 0xcc, 0xec, 0xf4, 0x34, 0xad, 0xcf, 0x97, 0x21, 0xf0, 0xd4,
0xef, 0xbc, 0xd2, 0xbd, 0x28, 0x24, 0x67, 0x96, 0x13, 0x78, 0x70, 0xa2, 0x64, 0x4a, 0xc7, 0x42,
0xfe, 0x44, 0x1d, 0x0b, 0xb1, 0x07, 0xf4, 0xc2, 0x31, 0x1e, 0xd0, 0x13, 0xbb, 0x0f, 0x86, 0x4e,
0xd0, 0x7d, 0x70, 0x92, 0x76, 0x81, 0x84, 0x20, 0x36, 0xb0, 0x7b, 0xf5, 0x45, 0x38, 0x2f, 0xc4,
0x28, 0x7f, 0xc9, 0xd7, 0xa9, 0x65, 0x68, 0x1a, 0xb1, 0x96, 0x7a, 0xdd, 0x6e, 0x5f, 0x7e, 0x0b,
0xc6, 0xc3, 0x3d, 0x2a, 0xce, 0x4e, 0x3b, 0x6d, 0x32, 0xe2, 0xad, 0x34, 0xb0, 0xd3, 0xce, 0x38,
0xf6, 0x38, 0xe4, 0xbf, 0x97, 0x60, 0x36, 0xb9, 0x17, 0x15, 0x69, 0x30, 0xde, 0x55, 0x0e, 0x82,
0xfd, 0xc1, 0xd2, 0x09, 0x6f, 0xb1, 0x78, 0x73, 0xc2, 0x5a, 0x08, 0x0b, 0x47, 0xb0, 0xe5, 0xef,
0x25, 0x98, 0x4b, 0x69, 0x0b, 0x38, 0x5d, 0x4b, 0xd0, 0x07, 0x50, 0xea, 0x2a, 0x07, 0xcd, 0x9e,
0xd5, 0x21, 0x27, 0xbe, 0xb7, 0xe3, 0x11, 0x63, 0x4d, 0xa0, 0x60, 0x0f, 0x4f, 0xfe, 0x4f, 0x09,
0x5e, 0x48, 0xad, 0x65, 0xd0, 0xed, 0x50, 0x07, 0x83, 0x1c, 0xe9, 0x60, 0x40, 0x71, 0xc1, 0xe7,
0xd4, 0xc0, 0xf0, 0xb9, 0x04, 0xe5, 0xb4, 0xef, 0x3c, 0x74, 0x2b, 0x64, 0xe4, 0x4b, 0x11, 0x23,
0xa7, 0x62, 0x72, 0xcf, 0xc9, 0xc6, 0xff, 0x91, 0x60, 0x36, 0xf9, 0x7b, 0x17, 0xbd, 0x1e, 0xb2,
0xb0, 0x12, 0xb1, 0x70, 0x22, 0x22, 0x25, 0xec, 0xfb, 0x08, 0xc6, 0xc5, 0x57, 0xb1, 0x80, 0x11,
0x7b, 0x2f, 0x27, 0x45, 0x74, 0x01, 0xe1, 0xd6, 0xa0, 0xdc, 0xab, 0xc2, 0x63, 0x38, 0x82, 0x26,
0xff, 0x43, 0x0e, 0x86, 0x9a, 0x2d, 0x45, 0x23, 0xa7, 0x50, 0x0c, 0xbe, 0x1b, 0x2a, 0x06, 0x07,
0xfd, 0xc7, 0x11, 0xb7, 0x2a, 0xb5, 0x0e, 0xc4, 0x91, 0x3a, 0xf0, 0xd5, 0x4c, 0x68, 0x4f, 0x2f,
0x01, 0xff, 0x0c, 0x46, 0x3c, 0xa5, 0xc7, 0xcb, 0x4c, 0xf2, 0x7f, 0xe4, 0x60, 0x34, 0xa0, 0xe2,
0x98, 0x79, 0x6d, 0x27, 0x54, 0x0f, 0xe4, 0x33, 0x7c, 0x78, 0x04, 0x74, 0x55, 0xdd, 0x0a, 0xc0,
0xe9, 0x98, 0xf5, 0x7b, 0x24, 0xe3, 0x85, 0xc1, 0x5b, 0x30, 0x4e, 0x15, 0xab, 0x43, 0xa8, 0x77,
0x27, 0x9f, 0xe7, 0xbe, 0xe8, 0xf5, 0x59, 0x6f, 0x86, 0xa8, 0x38, 0xc2, 0x7d, 0xfe, 0x2e, 0x8c,
0x85, 0x94, 0x1d, 0xab, 0xe1, 0xf5, 0xff, 0x25, 0x78, 0x69, 0xe0, 0x8d, 0x09, 0xaa, 0x87, 0x0e,
0x49, 0x35, 0x72, 0x48, 0xe6, 0xd3, 0x01, 0x9e, 0x5f, 0xe3, 0x54, 0xfd, 0xda, 0xe3, 0xef, 0xe6,
0xcf, 0x7c, 0xf3, 0xdd, 0xfc, 0x99, 0x6f, 0xbf, 0x9b, 0x3f, 0xf3, 0xb7, 0x47, 0xf3, 0xd2, 0xe3,
0xa3, 0x79, 0xe9, 0x9b, 0xa3, 0x79, 0xe9, 0xdb, 0xa3, 0x79, 0xe9, 0x17, 0x47, 0xf3, 0xd2, 0xbf,
0x7c, 0x3f, 0x7f, 0xe6, 0x83, 0xa2, 0x80, 0xfb, 0x5d, 0x00, 0x00, 0x00, 0xff, 0xff, 0x66, 0xf0,
0x40, 0xcd, 0xc4, 0x3c, 0x00, 0x00,
}

View File

@ -30,6 +30,12 @@ import "k8s.io/apimachinery/pkg/util/intstr/generated.proto";
// Package-wide variables from generator "generated".
option go_package = "v1beta1";
// AllowedCSIDriver represents a single inline CSI Driver that is allowed to be used.
message AllowedCSIDriver {
// Name is the registered name of the CSI driver
optional string name = 1;
}
// AllowedFlexVolume represents a single Flexvolume that is allowed to be used.
// Deprecated: use AllowedFlexVolume from policy API Group instead.
message AllowedFlexVolume {
@ -865,6 +871,11 @@ message PodSecurityPolicySpec {
// +optional
repeated AllowedFlexVolume allowedFlexVolumes = 18;
// AllowedCSIDrivers is a whitelist of inline CSI drivers that must be explicitly set to be embedded within a pod spec.
// An empty value means no CSI drivers can run inline within a pod spec.
// +optional
repeated AllowedCSIDriver allowedCSIDrivers = 23;
// allowedUnsafeSysctls is a list of explicitly allowed unsafe sysctls, defaults to none.
// Each entry is either a plain sysctl name or ends in "*" in which case it is considered
// as a prefix of allowed sysctls. Single * means all unsafe sysctls are allowed.

View File

@ -928,6 +928,10 @@ type PodSecurityPolicySpec struct {
// is allowed in the "volumes" field.
// +optional
AllowedFlexVolumes []AllowedFlexVolume `json:"allowedFlexVolumes,omitempty" protobuf:"bytes,18,rep,name=allowedFlexVolumes"`
// AllowedCSIDrivers is a whitelist of inline CSI drivers that must be explicitly set to be embedded within a pod spec.
// An empty value means no CSI drivers can run inline within a pod spec.
// +optional
AllowedCSIDrivers []AllowedCSIDriver `json:"allowedCSIDrivers,omitempty" protobuf:"bytes,23,rep,name=allowedCSIDrivers"`
// allowedUnsafeSysctls is a list of explicitly allowed unsafe sysctls, defaults to none.
// Each entry is either a plain sysctl name or ends in "*" in which case it is considered
// as a prefix of allowed sysctls. Single * means all unsafe sysctls are allowed.
@ -998,6 +1002,7 @@ var (
ConfigMap FSType = "configMap"
Quobyte FSType = "quobyte"
AzureDisk FSType = "azureDisk"
CSI FSType = "csi"
All FSType = "*"
)
@ -1008,6 +1013,12 @@ type AllowedFlexVolume struct {
Driver string `json:"driver" protobuf:"bytes,1,opt,name=driver"`
}
// AllowedCSIDriver represents a single inline CSI Driver that is allowed to be used.
type AllowedCSIDriver struct {
// Name is the registered name of the CSI driver
Name string `json:"name" protobuf:"bytes,1,opt,name=name"`
}
// HostPortRange defines a range of host ports that will be enabled by a policy
// for pods to use. It requires both the start and end to be defined.
// Deprecated: use HostPortRange from policy API Group instead.

View File

@ -27,6 +27,15 @@ package v1beta1
// Those methods can be generated by using hack/update-generated-swagger-docs.sh
// AUTO-GENERATED FUNCTIONS START HERE. DO NOT EDIT.
var map_AllowedCSIDriver = map[string]string{
"": "AllowedCSIDriver represents a single inline CSI Driver that is allowed to be used.",
"name": "Name is the registered name of the CSI driver",
}
func (AllowedCSIDriver) SwaggerDoc() map[string]string {
return map_AllowedCSIDriver
}
var map_AllowedFlexVolume = map[string]string{
"": "AllowedFlexVolume represents a single Flexvolume that is allowed to be used. Deprecated: use AllowedFlexVolume from policy API Group instead.",
"driver": "driver is the name of the Flexvolume driver.",
@ -461,6 +470,7 @@ var map_PodSecurityPolicySpec = map[string]string{
"allowPrivilegeEscalation": "allowPrivilegeEscalation determines if a pod can request to allow privilege escalation. If unspecified, defaults to true.",
"allowedHostPaths": "allowedHostPaths is a white list of allowed host paths. Empty indicates that all host paths may be used.",
"allowedFlexVolumes": "allowedFlexVolumes is a whitelist of allowed Flexvolumes. Empty or nil indicates that all Flexvolumes may be used. This parameter is effective only when the usage of the Flexvolumes is allowed in the \"volumes\" field.",
"allowedCSIDrivers": "AllowedCSIDrivers is a whitelist of inline CSI drivers that must be explicitly set to be embedded within a pod spec. An empty value means no CSI drivers can run inline within a pod spec.",
"allowedUnsafeSysctls": "allowedUnsafeSysctls is a list of explicitly allowed unsafe sysctls, defaults to none. Each entry is either a plain sysctl name or ends in \"*\" in which case it is considered as a prefix of allowed sysctls. Single * means all unsafe sysctls are allowed. Kubelet has to whitelist all allowed unsafe sysctls explicitly to avoid rejection.\n\nExamples: e.g. \"foo/*\" allows \"foo/bar\", \"foo/baz\", etc. e.g. \"foo.*\" allows \"foo.bar\", \"foo.baz\", etc.",
"forbiddenSysctls": "forbiddenSysctls is a list of explicitly forbidden sysctls, defaults to none. Each entry is either a plain sysctl name or ends in \"*\" in which case it is considered as a prefix of forbidden sysctls. Single * means all sysctls are forbidden.\n\nExamples: e.g. \"foo/*\" forbids \"foo/bar\", \"foo/baz\", etc. e.g. \"foo.*\" forbids \"foo.bar\", \"foo.baz\", etc.",
"allowedProcMountTypes": "AllowedProcMountTypes is a whitelist of allowed ProcMountTypes. Empty or nil indicates that only the DefaultProcMountType may be used. This requires the ProcMountType feature flag to be enabled.",

View File

@ -27,6 +27,22 @@ import (
intstr "k8s.io/apimachinery/pkg/util/intstr"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *AllowedCSIDriver) DeepCopyInto(out *AllowedCSIDriver) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AllowedCSIDriver.
func (in *AllowedCSIDriver) DeepCopy() *AllowedCSIDriver {
if in == nil {
return nil
}
out := new(AllowedCSIDriver)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *AllowedFlexVolume) DeepCopyInto(out *AllowedFlexVolume) {
*out = *in
@ -1049,6 +1065,11 @@ func (in *PodSecurityPolicySpec) DeepCopyInto(out *PodSecurityPolicySpec) {
*out = make([]AllowedFlexVolume, len(*in))
copy(*out, *in)
}
if in.AllowedCSIDrivers != nil {
in, out := &in.AllowedCSIDrivers, &out.AllowedCSIDrivers
*out = make([]AllowedCSIDriver, len(*in))
copy(*out, *in)
}
if in.AllowedUnsafeSysctls != nil {
in, out := &in.AllowedUnsafeSysctls, &out.AllowedUnsafeSysctls
*out = make([]string, len(*in))

View File

@ -24,6 +24,7 @@ limitations under the License.
k8s.io/kubernetes/vendor/k8s.io/api/policy/v1beta1/generated.proto
It has these top-level messages:
AllowedCSIDriver
AllowedFlexVolume
AllowedHostPath
Eviction
@ -71,83 +72,88 @@ var _ = math.Inf
// proto package needs to be updated.
const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
func (m *AllowedCSIDriver) Reset() { *m = AllowedCSIDriver{} }
func (*AllowedCSIDriver) ProtoMessage() {}
func (*AllowedCSIDriver) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{0} }
func (m *AllowedFlexVolume) Reset() { *m = AllowedFlexVolume{} }
func (*AllowedFlexVolume) ProtoMessage() {}
func (*AllowedFlexVolume) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{0} }
func (*AllowedFlexVolume) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{1} }
func (m *AllowedHostPath) Reset() { *m = AllowedHostPath{} }
func (*AllowedHostPath) ProtoMessage() {}
func (*AllowedHostPath) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{1} }
func (*AllowedHostPath) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{2} }
func (m *Eviction) Reset() { *m = Eviction{} }
func (*Eviction) ProtoMessage() {}
func (*Eviction) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{2} }
func (*Eviction) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{3} }
func (m *FSGroupStrategyOptions) Reset() { *m = FSGroupStrategyOptions{} }
func (*FSGroupStrategyOptions) ProtoMessage() {}
func (*FSGroupStrategyOptions) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{3} }
func (*FSGroupStrategyOptions) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{4} }
func (m *HostPortRange) Reset() { *m = HostPortRange{} }
func (*HostPortRange) ProtoMessage() {}
func (*HostPortRange) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{4} }
func (*HostPortRange) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{5} }
func (m *IDRange) Reset() { *m = IDRange{} }
func (*IDRange) ProtoMessage() {}
func (*IDRange) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{5} }
func (*IDRange) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{6} }
func (m *PodDisruptionBudget) Reset() { *m = PodDisruptionBudget{} }
func (*PodDisruptionBudget) ProtoMessage() {}
func (*PodDisruptionBudget) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{6} }
func (*PodDisruptionBudget) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{7} }
func (m *PodDisruptionBudgetList) Reset() { *m = PodDisruptionBudgetList{} }
func (*PodDisruptionBudgetList) ProtoMessage() {}
func (*PodDisruptionBudgetList) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{7} }
func (*PodDisruptionBudgetList) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{8} }
func (m *PodDisruptionBudgetSpec) Reset() { *m = PodDisruptionBudgetSpec{} }
func (*PodDisruptionBudgetSpec) ProtoMessage() {}
func (*PodDisruptionBudgetSpec) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{8} }
func (*PodDisruptionBudgetSpec) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{9} }
func (m *PodDisruptionBudgetStatus) Reset() { *m = PodDisruptionBudgetStatus{} }
func (*PodDisruptionBudgetStatus) ProtoMessage() {}
func (*PodDisruptionBudgetStatus) Descriptor() ([]byte, []int) {
return fileDescriptorGenerated, []int{9}
return fileDescriptorGenerated, []int{10}
}
func (m *PodSecurityPolicy) Reset() { *m = PodSecurityPolicy{} }
func (*PodSecurityPolicy) ProtoMessage() {}
func (*PodSecurityPolicy) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{10} }
func (*PodSecurityPolicy) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{11} }
func (m *PodSecurityPolicyList) Reset() { *m = PodSecurityPolicyList{} }
func (*PodSecurityPolicyList) ProtoMessage() {}
func (*PodSecurityPolicyList) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{11} }
func (*PodSecurityPolicyList) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{12} }
func (m *PodSecurityPolicySpec) Reset() { *m = PodSecurityPolicySpec{} }
func (*PodSecurityPolicySpec) ProtoMessage() {}
func (*PodSecurityPolicySpec) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{12} }
func (*PodSecurityPolicySpec) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{13} }
func (m *RunAsGroupStrategyOptions) Reset() { *m = RunAsGroupStrategyOptions{} }
func (*RunAsGroupStrategyOptions) ProtoMessage() {}
func (*RunAsGroupStrategyOptions) Descriptor() ([]byte, []int) {
return fileDescriptorGenerated, []int{13}
return fileDescriptorGenerated, []int{14}
}
func (m *RunAsUserStrategyOptions) Reset() { *m = RunAsUserStrategyOptions{} }
func (*RunAsUserStrategyOptions) ProtoMessage() {}
func (*RunAsUserStrategyOptions) Descriptor() ([]byte, []int) {
return fileDescriptorGenerated, []int{14}
return fileDescriptorGenerated, []int{15}
}
func (m *SELinuxStrategyOptions) Reset() { *m = SELinuxStrategyOptions{} }
func (*SELinuxStrategyOptions) ProtoMessage() {}
func (*SELinuxStrategyOptions) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{15} }
func (*SELinuxStrategyOptions) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{16} }
func (m *SupplementalGroupsStrategyOptions) Reset() { *m = SupplementalGroupsStrategyOptions{} }
func (*SupplementalGroupsStrategyOptions) ProtoMessage() {}
func (*SupplementalGroupsStrategyOptions) Descriptor() ([]byte, []int) {
return fileDescriptorGenerated, []int{16}
return fileDescriptorGenerated, []int{17}
}
func init() {
proto.RegisterType((*AllowedCSIDriver)(nil), "k8s.io.api.policy.v1beta1.AllowedCSIDriver")
proto.RegisterType((*AllowedFlexVolume)(nil), "k8s.io.api.policy.v1beta1.AllowedFlexVolume")
proto.RegisterType((*AllowedHostPath)(nil), "k8s.io.api.policy.v1beta1.AllowedHostPath")
proto.RegisterType((*Eviction)(nil), "k8s.io.api.policy.v1beta1.Eviction")
@ -166,6 +172,28 @@ func init() {
proto.RegisterType((*SELinuxStrategyOptions)(nil), "k8s.io.api.policy.v1beta1.SELinuxStrategyOptions")
proto.RegisterType((*SupplementalGroupsStrategyOptions)(nil), "k8s.io.api.policy.v1beta1.SupplementalGroupsStrategyOptions")
}
func (m *AllowedCSIDriver) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *AllowedCSIDriver) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
dAtA[i] = 0xa
i++
i = encodeVarintGenerated(dAtA, i, uint64(len(m.Name)))
i += copy(dAtA[i:], m.Name)
return i, nil
}
func (m *AllowedFlexVolume) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
@ -872,6 +900,20 @@ func (m *PodSecurityPolicySpec) MarshalTo(dAtA []byte) (int, error) {
}
i += n18
}
if len(m.AllowedCSIDrivers) > 0 {
for _, msg := range m.AllowedCSIDrivers {
dAtA[i] = 0xba
i++
dAtA[i] = 0x1
i++
i = encodeVarintGenerated(dAtA, i, uint64(msg.Size()))
n, err := msg.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n
}
}
return i, nil
}
@ -1018,6 +1060,14 @@ func encodeVarintGenerated(dAtA []byte, offset int, v uint64) int {
dAtA[offset] = uint8(v)
return offset + 1
}
func (m *AllowedCSIDriver) Size() (n int) {
var l int
_ = l
l = len(m.Name)
n += 1 + l + sovGenerated(uint64(l))
return n
}
func (m *AllowedFlexVolume) Size() (n int) {
var l int
_ = l
@ -1251,6 +1301,12 @@ func (m *PodSecurityPolicySpec) Size() (n int) {
l = m.RunAsGroup.Size()
n += 2 + l + sovGenerated(uint64(l))
}
if len(m.AllowedCSIDrivers) > 0 {
for _, e := range m.AllowedCSIDrivers {
l = e.Size()
n += 2 + l + sovGenerated(uint64(l))
}
}
return n
}
@ -1321,6 +1377,16 @@ func sovGenerated(x uint64) (n int) {
func sozGenerated(x uint64) (n int) {
return sovGenerated(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (this *AllowedCSIDriver) String() string {
if this == nil {
return "nil"
}
s := strings.Join([]string{`&AllowedCSIDriver{`,
`Name:` + fmt.Sprintf("%v", this.Name) + `,`,
`}`,
}, "")
return s
}
func (this *AllowedFlexVolume) String() string {
if this == nil {
return "nil"
@ -1495,6 +1561,7 @@ func (this *PodSecurityPolicySpec) String() string {
`ForbiddenSysctls:` + fmt.Sprintf("%v", this.ForbiddenSysctls) + `,`,
`AllowedProcMountTypes:` + fmt.Sprintf("%v", this.AllowedProcMountTypes) + `,`,
`RunAsGroup:` + strings.Replace(fmt.Sprintf("%v", this.RunAsGroup), "RunAsGroupStrategyOptions", "RunAsGroupStrategyOptions", 1) + `,`,
`AllowedCSIDrivers:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.AllowedCSIDrivers), "AllowedCSIDriver", "AllowedCSIDriver", 1), `&`, ``, 1) + `,`,
`}`,
}, "")
return s
@ -1551,6 +1618,85 @@ func valueToStringGenerated(v interface{}) string {
pv := reflect.Indirect(rv).Interface()
return fmt.Sprintf("*%v", pv)
}
func (m *AllowedCSIDriver) 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: AllowedCSIDriver: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: AllowedCSIDriver: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Name", 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 > l {
return io.ErrUnexpectedEOF
}
m.Name = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipGenerated(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthGenerated
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *AllowedFlexVolume) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
@ -3637,6 +3783,37 @@ func (m *PodSecurityPolicySpec) Unmarshal(dAtA []byte) error {
return err
}
iNdEx = postIndex
case 23:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field AllowedCSIDrivers", 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 > l {
return io.ErrUnexpectedEOF
}
m.AllowedCSIDrivers = append(m.AllowedCSIDrivers, AllowedCSIDriver{})
if err := m.AllowedCSIDrivers[len(m.AllowedCSIDrivers)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipGenerated(dAtA[iNdEx:])
@ -4210,115 +4387,119 @@ func init() {
}
var fileDescriptorGenerated = []byte{
// 1756 bytes of a gzipped FileDescriptorProto
// 1809 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0xdd, 0x8e, 0xdb, 0xc6,
0x15, 0x5e, 0x5a, 0xfb, 0xa3, 0x9d, 0xfd, 0x9f, 0xfd, 0x29, 0xbd, 0xa8, 0x45, 0x47, 0x01, 0x0a,
0x37, 0x48, 0xa8, 0x78, 0x9d, 0xa4, 0x46, 0xd3, 0x16, 0x59, 0x5a, 0xbb, 0xf6, 0x06, 0xde, 0xae,
0x3a, 0xb2, 0x83, 0xb6, 0x70, 0x8b, 0x8e, 0xc4, 0x59, 0xed, 0x64, 0x29, 0x92, 0x9d, 0x19, 0x2a,
0xab, 0xbb, 0x5e, 0xf4, 0xa2, 0x97, 0x7d, 0x81, 0xa0, 0x0f, 0x50, 0xf4, 0xaa, 0x2f, 0xe1, 0x02,
0x45, 0x91, 0xcb, 0xa0, 0x17, 0x42, 0xad, 0x22, 0x2f, 0xe1, 0xab, 0x80, 0xa3, 0x21, 0x25, 0xfe,
0x49, 0x5e, 0x03, 0xf6, 0x1d, 0x39, 0xe7, 0xfb, 0xbe, 0x73, 0xe6, 0xcc, 0x99, 0x33, 0x43, 0x02,
0xeb, 0xf2, 0x3e, 0x37, 0xa9, 0x57, 0xbb, 0x0c, 0x5a, 0x84, 0xb9, 0x44, 0x10, 0x5e, 0xeb, 0x11,
0xd7, 0xf6, 0x58, 0x4d, 0x19, 0xb0, 0x4f, 0x6b, 0xbe, 0xe7, 0xd0, 0x76, 0xbf, 0xd6, 0xbb, 0xdb,
0x22, 0x02, 0xdf, 0xad, 0x75, 0x88, 0x4b, 0x18, 0x16, 0xc4, 0x36, 0x7d, 0xe6, 0x09, 0x0f, 0xde,
0x1c, 0x41, 0x4d, 0xec, 0x53, 0x73, 0x04, 0x35, 0x15, 0x74, 0xff, 0x83, 0x0e, 0x15, 0x17, 0x41,
0xcb, 0x6c, 0x7b, 0xdd, 0x5a, 0xc7, 0xeb, 0x78, 0x35, 0xc9, 0x68, 0x05, 0xe7, 0xf2, 0x4d, 0xbe,
0xc8, 0xa7, 0x91, 0xd2, 0x7e, 0x75, 0xc2, 0x69, 0xdb, 0x63, 0xa4, 0xd6, 0xcb, 0x78, 0xdb, 0xff,
0x68, 0x8c, 0xe9, 0xe2, 0xf6, 0x05, 0x75, 0x09, 0xeb, 0xd7, 0xfc, 0xcb, 0x4e, 0x38, 0xc0, 0x6b,
0x5d, 0x22, 0x70, 0x1e, 0xab, 0x56, 0xc4, 0x62, 0x81, 0x2b, 0x68, 0x97, 0x64, 0x08, 0x9f, 0xcc,
0x22, 0xf0, 0xf6, 0x05, 0xe9, 0xe2, 0x0c, 0xef, 0x5e, 0x11, 0x2f, 0x10, 0xd4, 0xa9, 0x51, 0x57,
0x70, 0xc1, 0xd2, 0xa4, 0xea, 0xa7, 0x60, 0xeb, 0xd0, 0x71, 0xbc, 0xaf, 0x88, 0x7d, 0xec, 0x90,
0xab, 0x2f, 0x3c, 0x27, 0xe8, 0x12, 0xf8, 0x23, 0xb0, 0x68, 0x33, 0xda, 0x23, 0x4c, 0xd7, 0x6e,
0x6b, 0x77, 0x96, 0xad, 0xf5, 0xe7, 0x03, 0x63, 0x6e, 0x38, 0x30, 0x16, 0xeb, 0x72, 0x14, 0x29,
0x6b, 0x95, 0x83, 0x0d, 0x45, 0x7e, 0xe4, 0x71, 0xd1, 0xc0, 0xe2, 0x02, 0x1e, 0x00, 0xe0, 0x63,
0x71, 0xd1, 0x60, 0xe4, 0x9c, 0x5e, 0x29, 0x3a, 0x54, 0x74, 0xd0, 0x88, 0x2d, 0x68, 0x02, 0x05,
0xdf, 0x07, 0x65, 0x46, 0xb0, 0x7d, 0xe6, 0x3a, 0x7d, 0xfd, 0xc6, 0x6d, 0xed, 0x4e, 0xd9, 0xda,
0x54, 0x8c, 0x32, 0x52, 0xe3, 0x28, 0x46, 0x54, 0xff, 0xab, 0x81, 0xf2, 0x51, 0x8f, 0xb6, 0x05,
0xf5, 0x5c, 0xf8, 0x07, 0x50, 0x0e, 0xf3, 0x6e, 0x63, 0x81, 0xa5, 0xb3, 0x95, 0x83, 0x0f, 0xcd,
0x71, 0x4d, 0xc4, 0x69, 0x30, 0xfd, 0xcb, 0x4e, 0x38, 0xc0, 0xcd, 0x10, 0x6d, 0xf6, 0xee, 0x9a,
0x67, 0xad, 0x2f, 0x49, 0x5b, 0x9c, 0x12, 0x81, 0xc7, 0xe1, 0x8d, 0xc7, 0x50, 0xac, 0x0a, 0x1d,
0xb0, 0x66, 0x13, 0x87, 0x08, 0x72, 0xe6, 0x87, 0x1e, 0xb9, 0x8c, 0x70, 0xe5, 0xe0, 0xde, 0xab,
0xb9, 0xa9, 0x4f, 0x52, 0xad, 0xad, 0xe1, 0xc0, 0x58, 0x4b, 0x0c, 0xa1, 0xa4, 0x78, 0xf5, 0x6b,
0x0d, 0xec, 0x1d, 0x37, 0x1f, 0x32, 0x2f, 0xf0, 0x9b, 0x22, 0x5c, 0xa7, 0x4e, 0x5f, 0x99, 0xe0,
0x4f, 0xc0, 0x3c, 0x0b, 0x1c, 0xa2, 0x72, 0xfa, 0xae, 0x0a, 0x7a, 0x1e, 0x05, 0x0e, 0x79, 0x39,
0x30, 0xb6, 0x53, 0xac, 0x27, 0x7d, 0x9f, 0x20, 0x49, 0x80, 0x9f, 0x83, 0x45, 0x86, 0xdd, 0x0e,
0x09, 0x43, 0x2f, 0xdd, 0x59, 0x39, 0xa8, 0x9a, 0x85, 0xbb, 0xc6, 0x3c, 0xa9, 0xa3, 0x10, 0x3a,
0x5e, 0x71, 0xf9, 0xca, 0x91, 0x52, 0xa8, 0x9e, 0x82, 0x35, 0xb9, 0xd4, 0x1e, 0x13, 0xd2, 0x02,
0x6f, 0x81, 0x52, 0x97, 0xba, 0x32, 0xa8, 0x05, 0x6b, 0x45, 0xb1, 0x4a, 0xa7, 0xd4, 0x45, 0xe1,
0xb8, 0x34, 0xe3, 0x2b, 0x99, 0xb3, 0x49, 0x33, 0xbe, 0x42, 0xe1, 0x78, 0xf5, 0x21, 0x58, 0x52,
0x1e, 0x27, 0x85, 0x4a, 0xd3, 0x85, 0x4a, 0x39, 0x42, 0x7f, 0xbf, 0x01, 0xb6, 0x1b, 0x9e, 0x5d,
0xa7, 0x9c, 0x05, 0x32, 0x5f, 0x56, 0x60, 0x77, 0x88, 0x78, 0x0b, 0xf5, 0xf1, 0x04, 0xcc, 0x73,
0x9f, 0xb4, 0x55, 0x59, 0x1c, 0x4c, 0xc9, 0x6d, 0x4e, 0x7c, 0x4d, 0x9f, 0xb4, 0xad, 0xd5, 0x68,
0x29, 0xc3, 0x37, 0x24, 0xd5, 0xe0, 0x33, 0xb0, 0xc8, 0x05, 0x16, 0x01, 0xd7, 0x4b, 0x52, 0xf7,
0xa3, 0x6b, 0xea, 0x4a, 0xee, 0x78, 0x15, 0x47, 0xef, 0x48, 0x69, 0x56, 0xff, 0xad, 0x81, 0x1f,
0xe4, 0xb0, 0x1e, 0x53, 0x2e, 0xe0, 0xb3, 0x4c, 0xc6, 0xcc, 0x57, 0xcb, 0x58, 0xc8, 0x96, 0xf9,
0x8a, 0x37, 0x6f, 0x34, 0x32, 0x91, 0xad, 0x26, 0x58, 0xa0, 0x82, 0x74, 0xa3, 0x52, 0x34, 0xaf,
0x37, 0x2d, 0x6b, 0x4d, 0x49, 0x2f, 0x9c, 0x84, 0x22, 0x68, 0xa4, 0x55, 0xfd, 0xcf, 0x8d, 0xdc,
0xe9, 0x84, 0xe9, 0x84, 0xe7, 0x60, 0xb5, 0x4b, 0xdd, 0xc3, 0x1e, 0xa6, 0x0e, 0x6e, 0xa9, 0xdd,
0x33, 0xad, 0x08, 0xc2, 0x5e, 0x69, 0x8e, 0x7a, 0xa5, 0x79, 0xe2, 0x8a, 0x33, 0xd6, 0x14, 0x8c,
0xba, 0x1d, 0x6b, 0x73, 0x38, 0x30, 0x56, 0x4f, 0x27, 0x94, 0x50, 0x42, 0x17, 0xfe, 0x0e, 0x94,
0x39, 0x71, 0x48, 0x5b, 0x78, 0xec, 0x7a, 0x1d, 0xe2, 0x31, 0x6e, 0x11, 0xa7, 0xa9, 0xa8, 0xd6,
0x6a, 0x98, 0xb7, 0xe8, 0x0d, 0xc5, 0x92, 0xd0, 0x01, 0xeb, 0x5d, 0x7c, 0xf5, 0xd4, 0xc5, 0xf1,
0x44, 0x4a, 0xaf, 0x39, 0x11, 0x38, 0x1c, 0x18, 0xeb, 0xa7, 0x09, 0x2d, 0x94, 0xd2, 0xae, 0x7e,
0x37, 0x0f, 0x6e, 0x16, 0x56, 0x15, 0xfc, 0x1c, 0x40, 0xaf, 0xc5, 0x09, 0xeb, 0x11, 0xfb, 0xe1,
0xe8, 0x34, 0xa1, 0x5e, 0xb4, 0x71, 0xf7, 0xd5, 0x02, 0xc1, 0xb3, 0x0c, 0x02, 0xe5, 0xb0, 0xe0,
0x9f, 0x35, 0xb0, 0x66, 0x8f, 0xdc, 0x10, 0xbb, 0xe1, 0xd9, 0x51, 0x61, 0x3c, 0x7c, 0x9d, 0x7a,
0x37, 0xeb, 0x93, 0x4a, 0x47, 0xae, 0x60, 0x7d, 0x6b, 0x57, 0x05, 0xb4, 0x96, 0xb0, 0xa1, 0xa4,
0x53, 0x78, 0x0a, 0xa0, 0x1d, 0x4b, 0x72, 0x75, 0xa6, 0xc9, 0x14, 0x2f, 0x58, 0xb7, 0x94, 0xc2,
0x6e, 0xc2, 0x6f, 0x04, 0x42, 0x39, 0x44, 0xf8, 0x0b, 0xb0, 0xde, 0x0e, 0x18, 0x23, 0xae, 0x78,
0x44, 0xb0, 0x23, 0x2e, 0xfa, 0xfa, 0xbc, 0x94, 0xda, 0x53, 0x52, 0xeb, 0x0f, 0x12, 0x56, 0x94,
0x42, 0x87, 0x7c, 0x9b, 0x70, 0xca, 0x88, 0x1d, 0xf1, 0x17, 0x92, 0xfc, 0x7a, 0xc2, 0x8a, 0x52,
0x68, 0x78, 0x1f, 0xac, 0x92, 0x2b, 0x9f, 0xb4, 0xa3, 0x9c, 0x2e, 0x4a, 0xf6, 0x8e, 0x62, 0xaf,
0x1e, 0x4d, 0xd8, 0x50, 0x02, 0xb9, 0xef, 0x00, 0x98, 0x4d, 0x22, 0xdc, 0x04, 0xa5, 0x4b, 0xd2,
0x1f, 0x9d, 0x3c, 0x28, 0x7c, 0x84, 0x9f, 0x81, 0x85, 0x1e, 0x76, 0x02, 0xa2, 0x6a, 0xfd, 0xbd,
0x57, 0xab, 0xf5, 0x27, 0xb4, 0x4b, 0xd0, 0x88, 0xf8, 0xd3, 0x1b, 0xf7, 0xb5, 0xea, 0xbf, 0x34,
0xb0, 0xd5, 0xf0, 0xec, 0x26, 0x69, 0x07, 0x8c, 0x8a, 0x7e, 0x43, 0xae, 0xf3, 0x5b, 0xe8, 0xd9,
0x28, 0xd1, 0xb3, 0x3f, 0x9c, 0x5e, 0x6b, 0xc9, 0xe8, 0x8a, 0x3a, 0x76, 0xf5, 0xb9, 0x06, 0x76,
0x33, 0xe8, 0xb7, 0xd0, 0x51, 0x7f, 0x95, 0xec, 0xa8, 0xef, 0x5f, 0x67, 0x32, 0x05, 0xfd, 0xf4,
0xbb, 0x8d, 0x9c, 0xa9, 0xc8, 0x6e, 0x1a, 0xde, 0xee, 0x18, 0xed, 0x51, 0x87, 0x74, 0x88, 0x2d,
0x27, 0x53, 0x9e, 0xb8, 0xdd, 0xc5, 0x16, 0x34, 0x81, 0x82, 0x1c, 0xec, 0xd9, 0xe4, 0x1c, 0x07,
0x8e, 0x38, 0xb4, 0xed, 0x07, 0xd8, 0xc7, 0x2d, 0xea, 0x50, 0x41, 0xd5, 0x75, 0x64, 0xd9, 0xfa,
0x74, 0x38, 0x30, 0xf6, 0xea, 0xb9, 0x88, 0x97, 0x03, 0xe3, 0x56, 0xf6, 0x5e, 0x6e, 0xc6, 0x90,
0x3e, 0x2a, 0x90, 0x86, 0x7d, 0xa0, 0x33, 0xf2, 0xc7, 0x20, 0xdc, 0x14, 0x75, 0xe6, 0xf9, 0x09,
0xb7, 0x25, 0xe9, 0xf6, 0xe7, 0xc3, 0x81, 0xa1, 0xa3, 0x02, 0xcc, 0x6c, 0xc7, 0x85, 0xf2, 0xf0,
0x4b, 0xb0, 0x8d, 0x47, 0x7d, 0x20, 0xe1, 0x75, 0x5e, 0x7a, 0xbd, 0x3f, 0x1c, 0x18, 0xdb, 0x87,
0x59, 0xf3, 0x6c, 0x87, 0x79, 0xa2, 0xb0, 0x06, 0x96, 0x7a, 0xf2, 0xca, 0xce, 0xf5, 0x05, 0xa9,
0xbf, 0x3b, 0x1c, 0x18, 0x4b, 0xa3, 0x5b, 0x7c, 0xa8, 0xb9, 0x78, 0xdc, 0x94, 0x17, 0xc1, 0x08,
0x05, 0x3f, 0x06, 0x2b, 0x17, 0x1e, 0x17, 0xbf, 0x24, 0xe2, 0x2b, 0x8f, 0x5d, 0xca, 0xc6, 0x50,
0xb6, 0xb6, 0xd5, 0x0a, 0xae, 0x3c, 0x1a, 0x9b, 0xd0, 0x24, 0x0e, 0xfe, 0x06, 0x2c, 0x5f, 0xa8,
0x6b, 0x1f, 0xd7, 0x97, 0x64, 0xa1, 0xdd, 0x99, 0x52, 0x68, 0x89, 0x2b, 0xa2, 0xb5, 0xa5, 0xe4,
0x97, 0xa3, 0x61, 0x8e, 0xc6, 0x6a, 0xf0, 0xc7, 0x60, 0x49, 0xbe, 0x9c, 0xd4, 0xf5, 0xb2, 0x8c,
0x66, 0x43, 0xc1, 0x97, 0x1e, 0x8d, 0x86, 0x51, 0x64, 0x8f, 0xa0, 0x27, 0x8d, 0x07, 0xfa, 0x72,
0x16, 0x7a, 0xd2, 0x78, 0x80, 0x22, 0x3b, 0x7c, 0x06, 0x96, 0x38, 0x79, 0x4c, 0xdd, 0xe0, 0x4a,
0x07, 0x72, 0xcb, 0xdd, 0x9d, 0x12, 0x6e, 0xf3, 0x48, 0x22, 0x53, 0x17, 0xee, 0xb1, 0xba, 0xb2,
0xa3, 0x48, 0x12, 0xda, 0x60, 0x99, 0x05, 0xee, 0x21, 0x7f, 0xca, 0x09, 0xd3, 0x57, 0x32, 0xa7,
0x7d, 0x5a, 0x1f, 0x45, 0xd8, 0xb4, 0x87, 0x38, 0x33, 0x31, 0x02, 0x8d, 0x85, 0xe1, 0x5f, 0x34,
0x00, 0x79, 0xe0, 0xfb, 0x0e, 0xe9, 0x12, 0x57, 0x60, 0x47, 0xde, 0xef, 0xb9, 0xbe, 0x2a, 0xfd,
0xfd, 0x6c, 0xda, 0x7c, 0x32, 0xa4, 0xb4, 0xe3, 0xf8, 0x98, 0xce, 0x42, 0x51, 0x8e, 0xcf, 0x30,
0x9d, 0xe7, 0x5c, 0x3e, 0xeb, 0x6b, 0x33, 0xd3, 0x99, 0xff, 0xfd, 0x32, 0x4e, 0xa7, 0xb2, 0xa3,
0x48, 0x12, 0x7e, 0x01, 0xf6, 0xa2, 0xaf, 0x3b, 0xe4, 0x79, 0xe2, 0x98, 0x3a, 0x84, 0xf7, 0xb9,
0x20, 0x5d, 0x7d, 0x5d, 0x2e, 0x73, 0x45, 0x31, 0xf7, 0x50, 0x2e, 0x0a, 0x15, 0xb0, 0x61, 0x17,
0x18, 0x51, 0x7b, 0x08, 0xf7, 0x4e, 0xdc, 0x9f, 0x8e, 0x78, 0x1b, 0x3b, 0xa3, 0x5b, 0xcb, 0x86,
0x74, 0xf0, 0xee, 0x70, 0x60, 0x18, 0xf5, 0xe9, 0x50, 0x34, 0x4b, 0x0b, 0xfe, 0x1a, 0xe8, 0xb8,
0xc8, 0xcf, 0xa6, 0xf4, 0xf3, 0xc3, 0xb0, 0xe7, 0x14, 0x3a, 0x28, 0x64, 0x43, 0x1f, 0x6c, 0xe2,
0xe4, 0x77, 0x36, 0xd7, 0xb7, 0xe4, 0x2e, 0x7c, 0x6f, 0xca, 0x3a, 0xa4, 0x3e, 0xcd, 0x2d, 0x5d,
0xa5, 0x71, 0x33, 0x65, 0xe0, 0x28, 0xa3, 0x0e, 0xaf, 0x00, 0xc4, 0xe9, 0xdf, 0x02, 0x5c, 0x87,
0x33, 0x8f, 0x98, 0xcc, 0xbf, 0x84, 0x71, 0xa9, 0x65, 0x4c, 0x1c, 0xe5, 0xf8, 0x80, 0x8f, 0xc1,
0x8e, 0x1a, 0x7d, 0xea, 0x72, 0x7c, 0x4e, 0x9a, 0x7d, 0xde, 0x16, 0x0e, 0xd7, 0xb7, 0x65, 0x7f,
0xd3, 0x87, 0x03, 0x63, 0xe7, 0x30, 0xc7, 0x8e, 0x72, 0x59, 0xf0, 0x33, 0xb0, 0x79, 0xee, 0xb1,
0x16, 0xb5, 0x6d, 0xe2, 0x46, 0x4a, 0x3b, 0x52, 0x69, 0x27, 0xcc, 0xc4, 0x71, 0xca, 0x86, 0x32,
0x68, 0xc8, 0xc1, 0xae, 0x52, 0x6e, 0x30, 0xaf, 0x7d, 0xea, 0x05, 0xae, 0x08, 0x5b, 0x2a, 0xd7,
0x77, 0xe3, 0x63, 0x64, 0xf7, 0x30, 0x0f, 0xf0, 0x72, 0x60, 0xdc, 0xce, 0x69, 0xe9, 0x09, 0x10,
0xca, 0xd7, 0x86, 0x36, 0x00, 0xb2, 0x0f, 0x8c, 0xb6, 0xdc, 0xde, 0xcc, 0x4f, 0x40, 0x14, 0x83,
0xd3, 0xbb, 0x6e, 0x3d, 0x3c, 0x99, 0xc7, 0x66, 0x34, 0xa1, 0x5b, 0xfd, 0x9b, 0x06, 0x6e, 0x16,
0x32, 0xe1, 0x27, 0x89, 0xff, 0x0d, 0xd5, 0xd4, 0xff, 0x06, 0x98, 0x25, 0xbe, 0x81, 0xdf, 0x0d,
0x5f, 0x6b, 0x40, 0x2f, 0xea, 0x9e, 0xf0, 0xe3, 0x44, 0x80, 0xef, 0xa4, 0x02, 0xdc, 0xca, 0xf0,
0xde, 0x40, 0x7c, 0xff, 0xd0, 0xc0, 0x5e, 0xfe, 0xe9, 0x01, 0xef, 0x25, 0xa2, 0x33, 0x52, 0xd1,
0x6d, 0xa4, 0x58, 0x2a, 0xb6, 0xdf, 0x83, 0x75, 0x75, 0xc6, 0x24, 0xff, 0x36, 0x25, 0x62, 0x0c,
0x2b, 0x29, 0xbc, 0x1e, 0x2a, 0x89, 0x68, 0xa5, 0xe5, 0x87, 0x5d, 0x72, 0x0c, 0xa5, 0xd4, 0xaa,
0xff, 0xd4, 0xc0, 0x3b, 0x33, 0x4f, 0x07, 0x68, 0x25, 0x42, 0x37, 0x53, 0xa1, 0x57, 0x8a, 0x05,
0xde, 0xcc, 0x4f, 0x27, 0xeb, 0x83, 0xe7, 0x2f, 0x2a, 0x73, 0xdf, 0xbc, 0xa8, 0xcc, 0x7d, 0xfb,
0xa2, 0x32, 0xf7, 0xa7, 0x61, 0x45, 0x7b, 0x3e, 0xac, 0x68, 0xdf, 0x0c, 0x2b, 0xda, 0xb7, 0xc3,
0x8a, 0xf6, 0xbf, 0x61, 0x45, 0xfb, 0xeb, 0xff, 0x2b, 0x73, 0xbf, 0x5d, 0x52, 0x72, 0xdf, 0x07,
0x00, 0x00, 0xff, 0xff, 0x15, 0x2e, 0xf4, 0x72, 0x59, 0x16, 0x00, 0x00,
0x15, 0x5e, 0x7a, 0xff, 0xb4, 0xb3, 0x3f, 0xd6, 0xce, 0xfe, 0x84, 0x5e, 0xd4, 0xa2, 0xc3, 0x00,
0x85, 0x9b, 0x26, 0x54, 0xbc, 0x76, 0x52, 0xa3, 0x69, 0x8b, 0x2c, 0x57, 0xbb, 0xf6, 0x06, 0xde,
0xac, 0x3a, 0xb2, 0x83, 0xb6, 0x70, 0x8b, 0x8e, 0xc4, 0x59, 0xed, 0x64, 0x29, 0x92, 0x9d, 0x19,
0x2a, 0xab, 0xbb, 0x5e, 0xf4, 0xa2, 0x97, 0x7d, 0x81, 0xa0, 0x0f, 0x50, 0xf4, 0xaa, 0x2f, 0xe1,
0x02, 0x45, 0x91, 0xcb, 0xa0, 0x05, 0x84, 0x5a, 0x45, 0x5f, 0xc2, 0x57, 0x05, 0x47, 0x43, 0x4a,
0xfc, 0x91, 0x64, 0x1b, 0xb0, 0xef, 0xc8, 0x39, 0xdf, 0xf7, 0x9d, 0xc3, 0x33, 0x67, 0xce, 0x0c,
0x07, 0xd8, 0x97, 0xf7, 0xb9, 0x45, 0xfd, 0xea, 0x65, 0xd8, 0x24, 0xcc, 0x23, 0x82, 0xf0, 0x6a,
0x97, 0x78, 0x8e, 0xcf, 0xaa, 0xca, 0x80, 0x03, 0x5a, 0x0d, 0x7c, 0x97, 0xb6, 0x7a, 0xd5, 0xee,
0x9d, 0x26, 0x11, 0xf8, 0x4e, 0xb5, 0x4d, 0x3c, 0xc2, 0xb0, 0x20, 0x8e, 0x15, 0x30, 0x5f, 0xf8,
0xf0, 0xc6, 0x10, 0x6a, 0xe1, 0x80, 0x5a, 0x43, 0xa8, 0xa5, 0xa0, 0x7b, 0x1f, 0xb6, 0xa9, 0xb8,
0x08, 0x9b, 0x56, 0xcb, 0xef, 0x54, 0xdb, 0x7e, 0xdb, 0xaf, 0x4a, 0x46, 0x33, 0x3c, 0x97, 0x6f,
0xf2, 0x45, 0x3e, 0x0d, 0x95, 0xf6, 0xcc, 0x31, 0xa7, 0x2d, 0x9f, 0x91, 0x6a, 0x37, 0xe7, 0x6d,
0xef, 0xde, 0x08, 0xd3, 0xc1, 0xad, 0x0b, 0xea, 0x11, 0xd6, 0xab, 0x06, 0x97, 0xed, 0x68, 0x80,
0x57, 0x3b, 0x44, 0xe0, 0x22, 0x56, 0x75, 0x12, 0x8b, 0x85, 0x9e, 0xa0, 0x1d, 0x92, 0x23, 0x7c,
0x32, 0x8b, 0xc0, 0x5b, 0x17, 0xa4, 0x83, 0x73, 0xbc, 0xbb, 0x93, 0x78, 0xa1, 0xa0, 0x6e, 0x95,
0x7a, 0x82, 0x0b, 0x96, 0x25, 0x99, 0xf7, 0x40, 0xf9, 0xc0, 0x75, 0xfd, 0xaf, 0x89, 0x73, 0xd8,
0x38, 0xa9, 0x31, 0xda, 0x25, 0x0c, 0xde, 0x02, 0x0b, 0x1e, 0xee, 0x10, 0x5d, 0xbb, 0xa5, 0xdd,
0x5e, 0xb1, 0xd7, 0x9e, 0xf5, 0x8d, 0xb9, 0x41, 0xdf, 0x58, 0xf8, 0x02, 0x77, 0x08, 0x92, 0x16,
0xf3, 0x53, 0xb0, 0xa9, 0x58, 0xc7, 0x2e, 0xb9, 0xfa, 0xd2, 0x77, 0xc3, 0x0e, 0x81, 0xdf, 0x07,
0x4b, 0x8e, 0x14, 0x50, 0xc4, 0x0d, 0x45, 0x5c, 0x1a, 0xca, 0x22, 0x65, 0x35, 0x39, 0xb8, 0xae,
0xc8, 0x0f, 0x7d, 0x2e, 0xea, 0x58, 0x5c, 0xc0, 0x7d, 0x00, 0x02, 0x2c, 0x2e, 0xea, 0x8c, 0x9c,
0xd3, 0x2b, 0x45, 0x87, 0x8a, 0x0e, 0xea, 0x89, 0x05, 0x8d, 0xa1, 0xe0, 0x07, 0xa0, 0xc4, 0x08,
0x76, 0xce, 0x3c, 0xb7, 0xa7, 0x5f, 0xbb, 0xa5, 0xdd, 0x2e, 0xd9, 0x65, 0xc5, 0x28, 0x21, 0x35,
0x8e, 0x12, 0x84, 0xf9, 0x2f, 0x0d, 0x94, 0x8e, 0xba, 0xb4, 0x25, 0xa8, 0xef, 0xc1, 0xdf, 0x82,
0x52, 0x34, 0x5b, 0x0e, 0x16, 0x58, 0x3a, 0x5b, 0xdd, 0xff, 0xc8, 0x1a, 0x55, 0x52, 0x92, 0x3c,
0x2b, 0xb8, 0x6c, 0x47, 0x03, 0xdc, 0x8a, 0xd0, 0x56, 0xf7, 0x8e, 0x75, 0xd6, 0xfc, 0x8a, 0xb4,
0xc4, 0x29, 0x11, 0x78, 0x14, 0xde, 0x68, 0x0c, 0x25, 0xaa, 0xd0, 0x05, 0xeb, 0x0e, 0x71, 0x89,
0x20, 0x67, 0x41, 0xe4, 0x91, 0xcb, 0x08, 0x57, 0xf7, 0xef, 0xbe, 0x9c, 0x9b, 0xda, 0x38, 0xd5,
0xde, 0x1c, 0xf4, 0x8d, 0xf5, 0xd4, 0x10, 0x4a, 0x8b, 0x9b, 0xdf, 0x68, 0x60, 0xf7, 0xb8, 0xf1,
0x80, 0xf9, 0x61, 0xd0, 0x10, 0xd1, 0xec, 0xb6, 0x7b, 0xca, 0x04, 0x7f, 0x04, 0x16, 0x58, 0xe8,
0xc6, 0x73, 0xf9, 0x5e, 0x3c, 0x97, 0x28, 0x74, 0xc9, 0x8b, 0xbe, 0xb1, 0x95, 0x61, 0x3d, 0xee,
0x05, 0x04, 0x49, 0x02, 0xfc, 0x1c, 0x2c, 0x31, 0xec, 0xb5, 0x49, 0x14, 0xfa, 0xfc, 0xed, 0xd5,
0x7d, 0xd3, 0x9a, 0xb8, 0xd6, 0xac, 0x93, 0x1a, 0x8a, 0xa0, 0xa3, 0x19, 0x97, 0xaf, 0x1c, 0x29,
0x05, 0xf3, 0x14, 0xac, 0xcb, 0xa9, 0xf6, 0x99, 0x90, 0x16, 0x78, 0x13, 0xcc, 0x77, 0xa8, 0x27,
0x83, 0x5a, 0xb4, 0x57, 0x15, 0x6b, 0xfe, 0x94, 0x7a, 0x28, 0x1a, 0x97, 0x66, 0x7c, 0x25, 0x73,
0x36, 0x6e, 0xc6, 0x57, 0x28, 0x1a, 0x37, 0x1f, 0x80, 0x65, 0xe5, 0x71, 0x5c, 0x68, 0x7e, 0xba,
0xd0, 0x7c, 0x81, 0xd0, 0x5f, 0xae, 0x81, 0xad, 0xba, 0xef, 0xd4, 0x28, 0x67, 0xa1, 0xcc, 0x97,
0x1d, 0x3a, 0x6d, 0x22, 0xde, 0x42, 0x7d, 0x3c, 0x06, 0x0b, 0x3c, 0x20, 0x2d, 0x55, 0x16, 0xfb,
0x53, 0x72, 0x5b, 0x10, 0x5f, 0x23, 0x20, 0xad, 0xd1, 0xb2, 0x8c, 0xde, 0x90, 0x54, 0x83, 0x4f,
0xc1, 0x12, 0x17, 0x58, 0x84, 0x5c, 0x9f, 0x97, 0xba, 0xf7, 0x5e, 0x51, 0x57, 0x72, 0x47, 0xb3,
0x38, 0x7c, 0x47, 0x4a, 0xd3, 0xfc, 0x87, 0x06, 0xde, 0x29, 0x60, 0x3d, 0xa2, 0x5c, 0xc0, 0xa7,
0xb9, 0x8c, 0x59, 0x2f, 0x97, 0xb1, 0x88, 0x2d, 0xf3, 0x95, 0x2c, 0xde, 0x78, 0x64, 0x2c, 0x5b,
0x0d, 0xb0, 0x48, 0x05, 0xe9, 0xc4, 0xa5, 0x68, 0xbd, 0xda, 0x67, 0xd9, 0xeb, 0x4a, 0x7a, 0xf1,
0x24, 0x12, 0x41, 0x43, 0x2d, 0xf3, 0x9f, 0xd7, 0x0a, 0x3f, 0x27, 0x4a, 0x27, 0x3c, 0x07, 0x6b,
0x1d, 0xea, 0x1d, 0x74, 0x31, 0x75, 0x71, 0x53, 0xad, 0x9e, 0x69, 0x45, 0x10, 0x75, 0x58, 0x6b,
0xd8, 0x61, 0xad, 0x13, 0x4f, 0x9c, 0xb1, 0x86, 0x60, 0xd4, 0x6b, 0xdb, 0xe5, 0x41, 0xdf, 0x58,
0x3b, 0x1d, 0x53, 0x42, 0x29, 0x5d, 0xf8, 0x6b, 0x50, 0xe2, 0xc4, 0x25, 0x2d, 0xe1, 0xb3, 0x57,
0xeb, 0x10, 0x8f, 0x70, 0x93, 0xb8, 0x0d, 0x45, 0xb5, 0xd7, 0xa2, 0xbc, 0xc5, 0x6f, 0x28, 0x91,
0x84, 0x2e, 0xd8, 0xe8, 0xe0, 0xab, 0x27, 0x1e, 0x4e, 0x3e, 0x64, 0xfe, 0x35, 0x3f, 0x04, 0x0e,
0xfa, 0xc6, 0xc6, 0x69, 0x4a, 0x0b, 0x65, 0xb4, 0xcd, 0xff, 0x2d, 0x80, 0x1b, 0x13, 0xab, 0x0a,
0x7e, 0x0e, 0xa0, 0xdf, 0xe4, 0x84, 0x75, 0x89, 0xf3, 0x60, 0xb8, 0x07, 0x51, 0x3f, 0x5e, 0xb8,
0x7b, 0x6a, 0x82, 0xe0, 0x59, 0x0e, 0x81, 0x0a, 0x58, 0xf0, 0x0f, 0x1a, 0x58, 0x77, 0x86, 0x6e,
0x88, 0x53, 0xf7, 0x9d, 0xb8, 0x30, 0x1e, 0xbc, 0x4e, 0xbd, 0x5b, 0xb5, 0x71, 0xa5, 0x23, 0x4f,
0xb0, 0x9e, 0xbd, 0xa3, 0x02, 0x5a, 0x4f, 0xd9, 0x50, 0xda, 0x29, 0x3c, 0x05, 0xd0, 0x49, 0x24,
0xb9, 0xda, 0xd3, 0x64, 0x8a, 0x17, 0xed, 0x9b, 0x4a, 0x61, 0x27, 0xe5, 0x37, 0x06, 0xa1, 0x02,
0x22, 0xfc, 0x19, 0xd8, 0x68, 0x85, 0x8c, 0x11, 0x4f, 0x3c, 0x24, 0xd8, 0x15, 0x17, 0x3d, 0x7d,
0x41, 0x4a, 0xed, 0x2a, 0xa9, 0x8d, 0xc3, 0x94, 0x15, 0x65, 0xd0, 0x11, 0xdf, 0x21, 0x9c, 0x32,
0xe2, 0xc4, 0xfc, 0xc5, 0x34, 0xbf, 0x96, 0xb2, 0xa2, 0x0c, 0x1a, 0xde, 0x07, 0x6b, 0xe4, 0x2a,
0x20, 0xad, 0x38, 0xa7, 0x4b, 0x92, 0xbd, 0xad, 0xd8, 0x6b, 0x47, 0x63, 0x36, 0x94, 0x42, 0xee,
0xb9, 0x00, 0xe6, 0x93, 0x08, 0xcb, 0x60, 0xfe, 0x92, 0xf4, 0x86, 0x3b, 0x0f, 0x8a, 0x1e, 0xe1,
0x67, 0x60, 0xb1, 0x8b, 0xdd, 0x90, 0xa8, 0x5a, 0x7f, 0xff, 0xe5, 0x6a, 0xfd, 0x31, 0xed, 0x10,
0x34, 0x24, 0xfe, 0xf8, 0xda, 0x7d, 0xcd, 0xfc, 0xbb, 0x06, 0x36, 0xeb, 0xbe, 0xd3, 0x20, 0xad,
0x90, 0x51, 0xd1, 0xab, 0xcb, 0x79, 0x7e, 0x0b, 0x3d, 0x1b, 0xa5, 0x7a, 0xf6, 0x47, 0xd3, 0x6b,
0x2d, 0x1d, 0xdd, 0xa4, 0x8e, 0x6d, 0x3e, 0xd3, 0xc0, 0x4e, 0x0e, 0xfd, 0x16, 0x3a, 0xea, 0xcf,
0xd3, 0x1d, 0xf5, 0x83, 0x57, 0xf9, 0x98, 0x09, 0xfd, 0xf4, 0xdf, 0xe5, 0x82, 0x4f, 0x91, 0xdd,
0x34, 0x3a, 0xdd, 0x31, 0xda, 0xa5, 0x2e, 0x69, 0x13, 0x47, 0x7e, 0x4c, 0x69, 0xec, 0x74, 0x97,
0x58, 0xd0, 0x18, 0x0a, 0x72, 0xb0, 0xeb, 0x90, 0x73, 0x1c, 0xba, 0xe2, 0xc0, 0x71, 0x0e, 0x71,
0x80, 0x9b, 0xd4, 0xa5, 0x82, 0xaa, 0xe3, 0xc8, 0x8a, 0xfd, 0xe9, 0xa0, 0x6f, 0xec, 0xd6, 0x0a,
0x11, 0x2f, 0xfa, 0xc6, 0xcd, 0xfc, 0x69, 0xde, 0x4a, 0x20, 0x3d, 0x34, 0x41, 0x1a, 0xf6, 0x80,
0xce, 0xc8, 0xef, 0xc2, 0x68, 0x51, 0xd4, 0x98, 0x1f, 0xa4, 0xdc, 0xce, 0x4b, 0xb7, 0x3f, 0x1d,
0xf4, 0x0d, 0x1d, 0x4d, 0xc0, 0xcc, 0x76, 0x3c, 0x51, 0x1e, 0x7e, 0x05, 0xb6, 0xb0, 0x3a, 0x87,
0x8f, 0x7b, 0x5d, 0x90, 0x5e, 0xef, 0x0f, 0xfa, 0xc6, 0xd6, 0x41, 0xde, 0x3c, 0xdb, 0x61, 0x91,
0x28, 0xac, 0x82, 0xe5, 0xae, 0x3c, 0xb2, 0x73, 0x7d, 0x51, 0xea, 0xef, 0x0c, 0xfa, 0xc6, 0xf2,
0xf0, 0x14, 0x1f, 0x69, 0x2e, 0x1d, 0x37, 0xe4, 0x41, 0x30, 0x46, 0xc1, 0x8f, 0xc1, 0xea, 0x85,
0xcf, 0xc5, 0x17, 0x44, 0x7c, 0xed, 0xb3, 0x4b, 0xd9, 0x18, 0x4a, 0xf6, 0x96, 0x9a, 0xc1, 0xd5,
0x87, 0x23, 0x13, 0x1a, 0xc7, 0xc1, 0x5f, 0x82, 0x95, 0x0b, 0x75, 0xec, 0xe3, 0xfa, 0xb2, 0x2c,
0xb4, 0xdb, 0x53, 0x0a, 0x2d, 0x75, 0x44, 0xb4, 0x37, 0x95, 0xfc, 0x4a, 0x3c, 0xcc, 0xd1, 0x48,
0x0d, 0xfe, 0x00, 0x2c, 0xcb, 0x97, 0x93, 0x9a, 0x5e, 0x92, 0xd1, 0x5c, 0x57, 0xf0, 0xe5, 0x87,
0xc3, 0x61, 0x14, 0xdb, 0x63, 0xe8, 0x49, 0xfd, 0x50, 0x5f, 0xc9, 0x43, 0x4f, 0xea, 0x87, 0x28,
0xb6, 0xc3, 0xa7, 0x60, 0x99, 0x93, 0x47, 0xd4, 0x0b, 0xaf, 0x74, 0x20, 0x97, 0xdc, 0x9d, 0x29,
0xe1, 0x36, 0x8e, 0x24, 0x32, 0x73, 0xe0, 0x1e, 0xa9, 0x2b, 0x3b, 0x8a, 0x25, 0xa1, 0x03, 0x56,
0x58, 0xe8, 0x1d, 0xf0, 0x27, 0x9c, 0x30, 0x7d, 0x35, 0xb7, 0xdb, 0x67, 0xf5, 0x51, 0x8c, 0xcd,
0x7a, 0x48, 0x32, 0x93, 0x20, 0xd0, 0x48, 0x18, 0xfe, 0x51, 0x03, 0x90, 0x87, 0x41, 0xe0, 0x92,
0x0e, 0xf1, 0x04, 0x76, 0xe5, 0xf9, 0x9e, 0xeb, 0x6b, 0xd2, 0xdf, 0x4f, 0xa6, 0x7d, 0x4f, 0x8e,
0x94, 0x75, 0x9c, 0x6c, 0xd3, 0x79, 0x28, 0x2a, 0xf0, 0x19, 0xa5, 0xf3, 0x9c, 0xcb, 0x67, 0x7d,
0x7d, 0x66, 0x3a, 0x8b, 0xff, 0x5f, 0x46, 0xe9, 0x54, 0x76, 0x14, 0x4b, 0xc2, 0x2f, 0xc1, 0x6e,
0xfc, 0x77, 0x87, 0x7c, 0x5f, 0x1c, 0x53, 0x97, 0xf0, 0x1e, 0x17, 0xa4, 0xa3, 0x6f, 0xc8, 0x69,
0xae, 0x28, 0xe6, 0x2e, 0x2a, 0x44, 0xa1, 0x09, 0x6c, 0xd8, 0x01, 0x46, 0xdc, 0x1e, 0xa2, 0xb5,
0x93, 0xf4, 0xa7, 0x23, 0xde, 0xc2, 0xee, 0xf0, 0xd4, 0x72, 0x5d, 0x3a, 0x78, 0x6f, 0xd0, 0x37,
0x8c, 0xda, 0x74, 0x28, 0x9a, 0xa5, 0x05, 0x7f, 0x01, 0x74, 0x3c, 0xc9, 0x4f, 0x59, 0xfa, 0xf9,
0x5e, 0xd4, 0x73, 0x26, 0x3a, 0x98, 0xc8, 0x86, 0x01, 0x28, 0xe3, 0xf4, 0x7f, 0x36, 0xd7, 0x37,
0xe5, 0x2a, 0x7c, 0x7f, 0xca, 0x3c, 0x64, 0x7e, 0xcd, 0x6d, 0x5d, 0xa5, 0xb1, 0x9c, 0x31, 0x70,
0x94, 0x53, 0x87, 0x57, 0x00, 0xe2, 0xec, 0xb5, 0x00, 0xd7, 0xe1, 0xcc, 0x2d, 0x26, 0x77, 0x97,
0x30, 0x2a, 0xb5, 0x9c, 0x89, 0xa3, 0x02, 0x1f, 0xf0, 0x11, 0xd8, 0x56, 0xa3, 0x4f, 0x3c, 0x8e,
0xcf, 0x49, 0xa3, 0xc7, 0x5b, 0xc2, 0xe5, 0xfa, 0x96, 0xec, 0x6f, 0xfa, 0xa0, 0x6f, 0x6c, 0x1f,
0x14, 0xd8, 0x51, 0x21, 0x0b, 0x7e, 0x06, 0xca, 0xe7, 0x3e, 0x6b, 0x52, 0xc7, 0x21, 0x5e, 0xac,
0xb4, 0x2d, 0x95, 0xb6, 0xa3, 0x4c, 0x1c, 0x67, 0x6c, 0x28, 0x87, 0x86, 0x1c, 0xec, 0x28, 0xe5,
0x3a, 0xf3, 0x5b, 0xa7, 0x7e, 0xe8, 0x89, 0xa8, 0xa5, 0x72, 0x7d, 0x27, 0xd9, 0x46, 0x76, 0x0e,
0x8a, 0x00, 0x2f, 0xfa, 0xc6, 0xad, 0x82, 0x96, 0x9e, 0x02, 0xa1, 0x62, 0x6d, 0xe8, 0x00, 0x20,
0xfb, 0xc0, 0x70, 0xc9, 0xed, 0xce, 0xfc, 0x05, 0x44, 0x09, 0x38, 0xbb, 0xea, 0x36, 0xa2, 0x9d,
0x79, 0x64, 0x46, 0x63, 0xba, 0x50, 0x80, 0x4d, 0x9c, 0xb9, 0x31, 0xe2, 0xfa, 0x3b, 0x72, 0x8e,
0x7f, 0x38, 0x7b, 0x8e, 0x13, 0x8e, 0x7d, 0x43, 0x4d, 0xf1, 0x66, 0xd6, 0xc2, 0x51, 0xde, 0x81,
0xf9, 0x67, 0x0d, 0xdc, 0x98, 0x18, 0x2f, 0xfc, 0x24, 0x75, 0xcb, 0x61, 0x66, 0x6e, 0x39, 0x60,
0x9e, 0xf8, 0x06, 0x2e, 0x39, 0xbe, 0xd1, 0x80, 0x3e, 0xa9, 0x67, 0xc3, 0x8f, 0x53, 0x01, 0xbe,
0x9b, 0x09, 0x70, 0x33, 0xc7, 0x7b, 0x03, 0xf1, 0xfd, 0x55, 0x03, 0xbb, 0xc5, 0x7b, 0x16, 0xbc,
0x9b, 0x8a, 0xce, 0xc8, 0x44, 0x77, 0x3d, 0xc3, 0x52, 0xb1, 0xfd, 0x06, 0x6c, 0xa8, 0x9d, 0x2d,
0x7d, 0xc7, 0x95, 0x8a, 0x31, 0xaa, 0xdf, 0xe8, 0x50, 0xaa, 0x24, 0xe2, 0xfa, 0x92, 0xbf, 0x93,
0xe9, 0x31, 0x94, 0x51, 0x33, 0xff, 0xa6, 0x81, 0x77, 0x67, 0xee, 0x49, 0xd0, 0x4e, 0x85, 0x6e,
0x65, 0x42, 0xaf, 0x4c, 0x16, 0x78, 0x33, 0x57, 0x5d, 0xf6, 0x87, 0xcf, 0x9e, 0x57, 0xe6, 0xbe,
0x7d, 0x5e, 0x99, 0xfb, 0xee, 0x79, 0x65, 0xee, 0xf7, 0x83, 0x8a, 0xf6, 0x6c, 0x50, 0xd1, 0xbe,
0x1d, 0x54, 0xb4, 0xef, 0x06, 0x15, 0xed, 0x3f, 0x83, 0x8a, 0xf6, 0xa7, 0xff, 0x56, 0xe6, 0x7e,
0xb5, 0xac, 0xe4, 0xfe, 0x1f, 0x00, 0x00, 0xff, 0xff, 0x6f, 0xf9, 0x85, 0x0c, 0x05, 0x17, 0x00,
0x00,
}

View File

@ -30,6 +30,12 @@ import "k8s.io/apimachinery/pkg/util/intstr/generated.proto";
// Package-wide variables from generator "generated".
option go_package = "v1beta1";
// AllowedCSIDriver represents a single inline CSI Driver that is allowed to be used.
message AllowedCSIDriver {
// Name is the registered name of the CSI driver
optional string name = 1;
}
// AllowedFlexVolume represents a single Flexvolume that is allowed to be used.
message AllowedFlexVolume {
// driver is the name of the Flexvolume driver.
@ -292,6 +298,11 @@ message PodSecurityPolicySpec {
// +optional
repeated AllowedFlexVolume allowedFlexVolumes = 18;
// AllowedCSIDrivers is a whitelist of inline CSI drivers that must be explicitly set to be embedded within a pod spec.
// An empty value means no CSI drivers can run inline within a pod spec.
// +optional
repeated AllowedCSIDriver allowedCSIDrivers = 23;
// allowedUnsafeSysctls is a list of explicitly allowed unsafe sysctls, defaults to none.
// Each entry is either a plain sysctl name or ends in "*" in which case it is considered
// as a prefix of allowed sysctls. Single * means all unsafe sysctls are allowed.

View File

@ -216,6 +216,10 @@ type PodSecurityPolicySpec struct {
// is allowed in the "volumes" field.
// +optional
AllowedFlexVolumes []AllowedFlexVolume `json:"allowedFlexVolumes,omitempty" protobuf:"bytes,18,rep,name=allowedFlexVolumes"`
// AllowedCSIDrivers is a whitelist of inline CSI drivers that must be explicitly set to be embedded within a pod spec.
// An empty value means no CSI drivers can run inline within a pod spec.
// +optional
AllowedCSIDrivers []AllowedCSIDriver `json:"allowedCSIDrivers,omitempty" protobuf:"bytes,23,rep,name=allowedCSIDrivers"`
// allowedUnsafeSysctls is a list of explicitly allowed unsafe sysctls, defaults to none.
// Each entry is either a plain sysctl name or ends in "*" in which case it is considered
// as a prefix of allowed sysctls. Single * means all unsafe sysctls are allowed.
@ -304,6 +308,12 @@ type AllowedFlexVolume struct {
Driver string `json:"driver" protobuf:"bytes,1,opt,name=driver"`
}
// AllowedCSIDriver represents a single inline CSI Driver that is allowed to be used.
type AllowedCSIDriver struct {
// Name is the registered name of the CSI driver
Name string `json:"name" protobuf:"bytes,1,opt,name=name"`
}
// HostPortRange defines a range of host ports that will be enabled by a policy
// for pods to use. It requires both the start and end to be defined.
type HostPortRange struct {

View File

@ -27,6 +27,15 @@ package v1beta1
// Those methods can be generated by using hack/update-generated-swagger-docs.sh
// AUTO-GENERATED FUNCTIONS START HERE. DO NOT EDIT.
var map_AllowedCSIDriver = map[string]string{
"": "AllowedCSIDriver represents a single inline CSI Driver that is allowed to be used.",
"name": "Name is the registered name of the CSI driver",
}
func (AllowedCSIDriver) SwaggerDoc() map[string]string {
return map_AllowedCSIDriver
}
var map_AllowedFlexVolume = map[string]string{
"": "AllowedFlexVolume represents a single Flexvolume that is allowed to be used.",
"driver": "driver is the name of the Flexvolume driver.",
@ -170,6 +179,7 @@ var map_PodSecurityPolicySpec = map[string]string{
"allowPrivilegeEscalation": "allowPrivilegeEscalation determines if a pod can request to allow privilege escalation. If unspecified, defaults to true.",
"allowedHostPaths": "allowedHostPaths is a white list of allowed host paths. Empty indicates that all host paths may be used.",
"allowedFlexVolumes": "allowedFlexVolumes is a whitelist of allowed Flexvolumes. Empty or nil indicates that all Flexvolumes may be used. This parameter is effective only when the usage of the Flexvolumes is allowed in the \"volumes\" field.",
"allowedCSIDrivers": "AllowedCSIDrivers is a whitelist of inline CSI drivers that must be explicitly set to be embedded within a pod spec. An empty value means no CSI drivers can run inline within a pod spec.",
"allowedUnsafeSysctls": "allowedUnsafeSysctls is a list of explicitly allowed unsafe sysctls, defaults to none. Each entry is either a plain sysctl name or ends in \"*\" in which case it is considered as a prefix of allowed sysctls. Single * means all unsafe sysctls are allowed. Kubelet has to whitelist all allowed unsafe sysctls explicitly to avoid rejection.\n\nExamples: e.g. \"foo/*\" allows \"foo/bar\", \"foo/baz\", etc. e.g. \"foo.*\" allows \"foo.bar\", \"foo.baz\", etc.",
"forbiddenSysctls": "forbiddenSysctls is a list of explicitly forbidden sysctls, defaults to none. Each entry is either a plain sysctl name or ends in \"*\" in which case it is considered as a prefix of forbidden sysctls. Single * means all sysctls are forbidden.\n\nExamples: e.g. \"foo/*\" forbids \"foo/bar\", \"foo/baz\", etc. e.g. \"foo.*\" forbids \"foo.bar\", \"foo.baz\", etc.",
"allowedProcMountTypes": "AllowedProcMountTypes is a whitelist of allowed ProcMountTypes. Empty or nil indicates that only the DefaultProcMountType may be used. This requires the ProcMountType feature flag to be enabled.",

View File

@ -27,6 +27,22 @@ import (
intstr "k8s.io/apimachinery/pkg/util/intstr"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *AllowedCSIDriver) DeepCopyInto(out *AllowedCSIDriver) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AllowedCSIDriver.
func (in *AllowedCSIDriver) DeepCopy() *AllowedCSIDriver {
if in == nil {
return nil
}
out := new(AllowedCSIDriver)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *AllowedFlexVolume) DeepCopyInto(out *AllowedFlexVolume) {
*out = *in
@ -375,6 +391,11 @@ func (in *PodSecurityPolicySpec) DeepCopyInto(out *PodSecurityPolicySpec) {
*out = make([]AllowedFlexVolume, len(*in))
copy(*out, *in)
}
if in.AllowedCSIDrivers != nil {
in, out := &in.AllowedCSIDrivers, &out.AllowedCSIDrivers
*out = make([]AllowedCSIDriver, len(*in))
copy(*out, *in)
}
if in.AllowedUnsafeSysctls != nil {
in, out := &in.AllowedUnsafeSysctls, &out.AllowedUnsafeSysctls
*out = make([]string, len(*in))