Fix up YAML serialisation to understand AutoRest property renaming (#209)
This commit is contained in:
committed by
Kubernetes Prow Robot
parent
9bbe42201f
commit
9f1669b0cb
@@ -1,4 +1,8 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using YamlDotNet.Core;
|
using YamlDotNet.Core;
|
||||||
@@ -29,6 +33,7 @@ namespace k8s
|
|||||||
var deserializer =
|
var deserializer =
|
||||||
new DeserializerBuilder()
|
new DeserializerBuilder()
|
||||||
.WithNamingConvention(new CamelCaseNamingConvention())
|
.WithNamingConvention(new CamelCaseNamingConvention())
|
||||||
|
.WithTypeInspector(ti => new AutoRestTypeInspector(ti))
|
||||||
.Build();
|
.Build();
|
||||||
var obj = deserializer.Deserialize<T>(content);
|
var obj = deserializer.Deserialize<T>(content);
|
||||||
return obj;
|
return obj;
|
||||||
@@ -43,6 +48,7 @@ namespace k8s
|
|||||||
var serializer =
|
var serializer =
|
||||||
new SerializerBuilder()
|
new SerializerBuilder()
|
||||||
.WithNamingConvention(new CamelCaseNamingConvention())
|
.WithNamingConvention(new CamelCaseNamingConvention())
|
||||||
|
.WithTypeInspector(ti => new AutoRestTypeInspector(ti))
|
||||||
.BuildValueSerializer();
|
.BuildValueSerializer();
|
||||||
emitter.Emit(new StreamStart());
|
emitter.Emit(new StreamStart());
|
||||||
emitter.Emit(new DocumentStart());
|
emitter.Emit(new DocumentStart());
|
||||||
@@ -50,5 +56,88 @@ namespace k8s
|
|||||||
|
|
||||||
return stringBuilder.ToString();
|
return stringBuilder.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class AutoRestTypeInspector : ITypeInspector
|
||||||
|
{
|
||||||
|
private readonly ITypeInspector _inner;
|
||||||
|
|
||||||
|
public AutoRestTypeInspector(ITypeInspector inner)
|
||||||
|
{
|
||||||
|
_inner = inner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<IPropertyDescriptor> GetProperties(Type type, object container)
|
||||||
|
{
|
||||||
|
var pds = _inner.GetProperties(type, container);
|
||||||
|
return pds.Select(pd => TrimPropertySuffix(pd, type)).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IPropertyDescriptor GetProperty(Type type, object container, string name, bool ignoreUnmatched)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return _inner.GetProperty(type, container, name, ignoreUnmatched);
|
||||||
|
}
|
||||||
|
catch (System.Runtime.Serialization.SerializationException)
|
||||||
|
{
|
||||||
|
return _inner.GetProperty(type, container, name + "Property", ignoreUnmatched);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IPropertyDescriptor TrimPropertySuffix(IPropertyDescriptor pd, Type type)
|
||||||
|
{
|
||||||
|
if (!pd.Name.EndsWith("Property"))
|
||||||
|
{
|
||||||
|
return pd;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This might have been renamed by AutoRest. See if there is a
|
||||||
|
// JsonPropertyAttribute.PropertyName and use that instead if there is.
|
||||||
|
var jpa = pd.GetCustomAttribute<JsonPropertyAttribute>();
|
||||||
|
if (jpa == null || String.IsNullOrEmpty(jpa.PropertyName))
|
||||||
|
{
|
||||||
|
return pd;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new RenamedPropertyDescriptor(pd, jpa.PropertyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class RenamedPropertyDescriptor : IPropertyDescriptor
|
||||||
|
{
|
||||||
|
private readonly IPropertyDescriptor _inner;
|
||||||
|
private readonly string _name;
|
||||||
|
|
||||||
|
public RenamedPropertyDescriptor(IPropertyDescriptor inner, string name)
|
||||||
|
{
|
||||||
|
_inner = inner;
|
||||||
|
_name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name => _name;
|
||||||
|
|
||||||
|
public bool CanWrite => _inner.CanWrite;
|
||||||
|
|
||||||
|
public Type Type => _inner.Type;
|
||||||
|
|
||||||
|
public Type TypeOverride { get => _inner.TypeOverride; set => _inner.TypeOverride = value; }
|
||||||
|
public int Order { get => _inner.Order; set => _inner.Order = value; }
|
||||||
|
public ScalarStyle ScalarStyle { get => _inner.ScalarStyle; set => _inner.ScalarStyle = value; }
|
||||||
|
|
||||||
|
public T GetCustomAttribute<T>() where T : Attribute
|
||||||
|
{
|
||||||
|
return _inner.GetCustomAttribute<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IObjectDescriptor Read(object target)
|
||||||
|
{
|
||||||
|
return _inner.Read(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Write(object target, object value)
|
||||||
|
{
|
||||||
|
_inner.Write(target, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,48 @@ metadata:
|
|||||||
Assert.Equal("foo", obj.Metadata.Name);
|
Assert.Equal("foo", obj.Metadata.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void LoadNamespacedFromString()
|
||||||
|
{
|
||||||
|
var content = @"apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
namespace: bar
|
||||||
|
name: foo
|
||||||
|
";
|
||||||
|
|
||||||
|
var obj = Yaml.LoadFromString<V1Pod>(content);
|
||||||
|
|
||||||
|
Assert.Equal("foo", obj.Metadata.Name);
|
||||||
|
Assert.Equal("bar", obj.Metadata.NamespaceProperty);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void LoadPropertyNamedReadOnlyFromString()
|
||||||
|
{
|
||||||
|
var content = @"apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
namespace: bar
|
||||||
|
name: foo
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx
|
||||||
|
volumeMounts:
|
||||||
|
- name: vm1
|
||||||
|
mountPath: /vm1
|
||||||
|
readOnly: true
|
||||||
|
- name: vm2
|
||||||
|
mountPath: /vm2
|
||||||
|
readOnly: false
|
||||||
|
";
|
||||||
|
|
||||||
|
var obj = Yaml.LoadFromString<V1Pod>(content);
|
||||||
|
|
||||||
|
Assert.True(obj.Spec.Containers[0].VolumeMounts[0].ReadOnlyProperty);
|
||||||
|
Assert.False(obj.Spec.Containers[0].VolumeMounts[1].ReadOnlyProperty);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void LoadFromStream()
|
public void LoadFromStream()
|
||||||
{
|
{
|
||||||
@@ -59,6 +101,85 @@ metadata:
|
|||||||
name: foo").SequenceEqual(ToLines(yaml)));
|
name: foo").SequenceEqual(ToLines(yaml)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void WriteNamespacedToString()
|
||||||
|
{
|
||||||
|
var pod = new V1Pod()
|
||||||
|
{
|
||||||
|
ApiVersion = "v1",
|
||||||
|
Kind = "Pod",
|
||||||
|
Metadata = new V1ObjectMeta()
|
||||||
|
{
|
||||||
|
Name = "foo",
|
||||||
|
NamespaceProperty = "bar"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var yaml = Yaml.SaveToString(pod);
|
||||||
|
Assert.True(ToLines(@"apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: foo
|
||||||
|
namespace: bar").SequenceEqual(ToLines(yaml)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void WritePropertyNamedReadOnlyToString()
|
||||||
|
{
|
||||||
|
var pod = new V1Pod()
|
||||||
|
{
|
||||||
|
ApiVersion = "v1",
|
||||||
|
Kind = "Pod",
|
||||||
|
Metadata = new V1ObjectMeta()
|
||||||
|
{
|
||||||
|
Name = "foo",
|
||||||
|
NamespaceProperty = "bar"
|
||||||
|
},
|
||||||
|
Spec = new V1PodSpec()
|
||||||
|
{
|
||||||
|
Containers = new[]
|
||||||
|
{
|
||||||
|
new V1Container()
|
||||||
|
{
|
||||||
|
Image = "nginx",
|
||||||
|
VolumeMounts = new[]
|
||||||
|
{
|
||||||
|
new V1VolumeMount
|
||||||
|
{
|
||||||
|
Name = "vm1",
|
||||||
|
MountPath = "/vm1",
|
||||||
|
ReadOnlyProperty = true
|
||||||
|
},
|
||||||
|
new V1VolumeMount
|
||||||
|
{
|
||||||
|
Name = "vm2",
|
||||||
|
MountPath = "/vm2",
|
||||||
|
ReadOnlyProperty = false
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var yaml = Yaml.SaveToString(pod);
|
||||||
|
Assert.True(ToLines(@"apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: foo
|
||||||
|
namespace: bar
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx
|
||||||
|
volumeMounts:
|
||||||
|
- mountPath: /vm1
|
||||||
|
name: vm1
|
||||||
|
readOnly: true
|
||||||
|
- mountPath: /vm2
|
||||||
|
name: vm2
|
||||||
|
readOnly: false").SequenceEqual(ToLines(yaml)));
|
||||||
|
}
|
||||||
|
|
||||||
private static IEnumerable<string> ToLines(string s)
|
private static IEnumerable<string> ToLines(string s)
|
||||||
{
|
{
|
||||||
using (var reader = new StringReader(s))
|
using (var reader = new StringReader(s))
|
||||||
|
|||||||
Reference in New Issue
Block a user