Skip to content

Commit bbd3b6c

Browse files
authored
Support round-trip CRD (de)serialization (#1034)
* Support round-trip CRD (de)serialization * Add a floating point emitter to fix UT * Unused using * Stylecop * Reduce warnings
1 parent dec73d4 commit bbd3b6c

File tree

4 files changed

+85
-1
lines changed

4 files changed

+85
-1
lines changed

Diff for: src/KubernetesClient.Models/FloatEmitter.cs

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using YamlDotNet.Core;
2+
using YamlDotNet.Core.Events;
3+
using YamlDotNet.Serialization;
4+
using YamlDotNet.Serialization.EventEmitters;
5+
6+
namespace k8s
7+
{
8+
internal class FloatEmitter : ChainedEventEmitter
9+
{
10+
public FloatEmitter(IEventEmitter nextEmitter)
11+
: base(nextEmitter)
12+
{
13+
}
14+
15+
public override void Emit(ScalarEventInfo eventInfo, IEmitter emitter)
16+
{
17+
switch (eventInfo.Source.Value)
18+
{
19+
// Floating point numbers should always render at least one zero (e.g. 1.0f => '1.0' not '1')
20+
case double d:
21+
emitter.Emit(new Scalar(d.ToString("0.0######################")));
22+
break;
23+
case float f:
24+
emitter.Emit(new Scalar(f.ToString("0.0######################")));
25+
break;
26+
default:
27+
base.Emit(eventInfo, emitter);
28+
break;
29+
}
30+
}
31+
}
32+
}

Diff for: src/KubernetesClient.Models/KubernetesYaml.cs

+2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ public static class KubernetesYaml
2121
.WithTypeConverter(new IntOrStringYamlConverter())
2222
.WithTypeConverter(new ByteArrayStringYamlConverter())
2323
.WithTypeConverter(new ResourceQuantityYamlConverter())
24+
.WithAttemptingUnquotedStringTypeDeserialization()
2425
.WithOverridesFromJsonPropertyAttributes()
2526
.IgnoreUnmatchedProperties()
2627
.Build();
@@ -33,6 +34,7 @@ public static class KubernetesYaml
3334
.WithTypeConverter(new ByteArrayStringYamlConverter())
3435
.WithTypeConverter(new ResourceQuantityYamlConverter())
3536
.WithEventEmitter(e => new StringQuotingEmitter(e))
37+
.WithEventEmitter(e => new FloatEmitter(e))
3638
.ConfigureDefaultValuesHandling(DefaultValuesHandling.OmitNull)
3739
.WithOverridesFromJsonPropertyAttributes()
3840
.BuildValueSerializer();

Diff for: src/KubernetesClient/CertUtils.cs

-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,6 @@ public static X509Certificate2 GeneratePfx(KubernetesClientConfiguration config)
104104
{
105105
cert = new X509Certificate2(cert.Export(X509ContentType.Pkcs12));
106106
}
107-
108107
}
109108

110109
return cert;

Diff for: tests/KubernetesClient.Tests/KubernetesYamlTests.cs

+51
Original file line numberDiff line numberDiff line change
@@ -841,5 +841,56 @@ public void DeserializeWithJsonPropertyName()
841841
var ver = result.Spec.Versions[0];
842842
Assert.Equal(true, ver?.Schema?.OpenAPIV3Schema?.XKubernetesIntOrString);
843843
}
844+
845+
#pragma warning disable CA1812 // Class is used for YAML deserialization tests
846+
[KubernetesEntity(Group = KubeGroup, Kind = KubeKind, ApiVersion = KubeApiVersion, PluralName = KubePluralName)]
847+
private sealed class V1AlphaFoo : IKubernetesObject<V1ObjectMeta>, ISpec<Dictionary<string, object>>
848+
{
849+
public const string KubeApiVersion = "v1alpha";
850+
public const string KubeKind = "foo";
851+
public const string KubeGroup = "foo.bar";
852+
public const string KubePluralName = "foos";
853+
854+
public string ApiVersion { get; set; }
855+
public string Kind { get; set; }
856+
public V1ObjectMeta Metadata { get; set; }
857+
public Dictionary<string, object> Spec { get; set; }
858+
859+
public V1AlphaFoo()
860+
{
861+
Metadata = new V1ObjectMeta();
862+
Spec = new Dictionary<string, object>();
863+
}
864+
}
865+
#pragma warning restore CA1812 // Class is used for YAML deserialization tests
866+
867+
[Fact]
868+
public void LoadAllFromStringWithTypeMapGenericCRD()
869+
{
870+
var content = @"apiVersion: foo.bar/v1alpha
871+
kind: Foo
872+
metadata:
873+
name: foo
874+
namespace: ns
875+
spec:
876+
bool: false
877+
byte: 123
878+
float: 12.0
879+
";
880+
881+
var objs = KubernetesYaml.LoadAllFromString(content, new Dictionary<string, Type>
882+
{
883+
{ $"{V1AlphaFoo.KubeGroup}/{V1AlphaFoo.KubeApiVersion}/Foo", typeof(V1AlphaFoo) },
884+
});
885+
Assert.Single(objs);
886+
var v1AlphaFoo = Assert.IsType<V1AlphaFoo>(objs[0]);
887+
Assert.Equal("foo", v1AlphaFoo.Metadata.Name);
888+
Assert.Equal("ns", v1AlphaFoo.Metadata.NamespaceProperty);
889+
Assert.Equal(3, v1AlphaFoo.Spec.Count);
890+
Assert.False(Assert.IsType<bool>(v1AlphaFoo.Spec["bool"]));
891+
Assert.Equal(123, Assert.IsType<byte>(v1AlphaFoo.Spec["byte"]));
892+
Assert.Equal(12.0, Assert.IsType<float>(v1AlphaFoo.Spec["float"]), 3);
893+
Assert.Equal(content.Replace("\r\n", "\n"), KubernetesYaml.SerializeAll(objs).Replace("\r\n", "\n"));
894+
}
844895
}
845896
}

0 commit comments

Comments
 (0)