-
Notifications
You must be signed in to change notification settings - Fork 307
Description
Describe the bug
Timestamp deserialization is more limited than Kubernetes API conventions allow. I.e., there are timestamps that are fine according to Kubernetes API conventions (e.g., lastTransitionTimestamp
in status conditions) that can not be deserialized using the C# Kubernetes client but instead raise an exception like shown below.
More precisely, the C# Kubernetes client only allows either exactly 6 digits for nanoseconds or none at all, whereas an arbitrary number < 10 is actually possible.
Kubernetes C# SDK Client Version
Observed on 10.0.31
, but according to the implementation of KubernetesDateTimeOffsetConverter
on the master branch we expect the bug to occur on master as well.
Server Kubernetes Version
1.24.14
Dotnet Runtime Version
net6
To Reproduce
Create a Kubernetes resource with a status condition where the lastTransitionTimestamp
has e.g. 9 nanosecond positions.
Attempt to read the resource with the generic client of the C# Kubernetes Client. The exception shown below will be thrown.
Expected behavior
The Kubernetes resource should be read properly, including the lastTransitionTimestamp
of the status condition.
Where do you run your app with Kubernetes SDK (please complete the following information):
The Kubernetes SDK is used in a container running the image mcr.microsoft.com/dotnet/sdk:6.0-alpine3.16
in Kubernetes 1.24.14
.
Additional context
According to the Kubernetes API conventions, the lastTransitionTimestamp should be deserializable as a Golang Time struct. The deserialization of a string into such a struct follows the conventions of RFC3339 and its implementation in particular allows an arbitrary number of nanosecond digits from 0 to 9.
We actually faced this problem in practice trying to read a KafkaConnector
resource by the Strimzi operator that contained a status condition with the lastTransitionTimestamp
as shown in the exception below. According to the Kubernetes API conventions, this timestamp is well-formatted and should be deserialized correctly.
The KubernetesDateTimeOffsetConverter
in the C# Kubernetes Client however only allows either 0 or 6 nanosecond digits.
Exception
System.FormatException: String '2023-07-26T11:17:34.255606088Z' was not recognized as a valid DateTime.
at System.DateTimeParse.ParseExactMultiple(ReadOnlySpan`1 s, String[] formats, DateTimeFormatInfo dtfi, DateTimeStyles style, TimeSpan& offset)
at System.DateTimeOffset.ParseExact(String input, String[] formats, IFormatProvider formatProvider, DateTimeStyles styles)
at k8s.KubernetesJson.KubernetesDateTimeConverter.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.ReadJsonAndSetMember(Object obj, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
at System.Text.Json.Serialization.JsonCollectionConverter`2.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, TCollection& value)
at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.ReadJsonAndSetMember(Object obj, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.ReadJsonAndSetMember(Object obj, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.Serialization.Converters.ObjectWithParameterizedConstructorConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
at System.Text.Json.JsonSerializer.ReadFromSpan[TValue](ReadOnlySpan`1 utf8Json, JsonTypeInfo jsonTypeInfo, Nullable`1 actualByteCount)
at System.Text.Json.JsonSerializer.ReadFromSpan[TValue](ReadOnlySpan`1 json, JsonTypeInfo jsonTypeInfo)
at System.Text.Json.JsonSerializer.Deserialize[TValue](String json, JsonSerializerOptions options)
at k8s.GenericClient.ReadNamespacedAsync[T](String ns, String name, CancellationToken cancel)