serialise sdk side

This commit is contained in:
Fraser Waters 2021-11-12 17:45:20 +00:00
parent 85886b31ca
commit f1f1b80deb
9 changed files with 82 additions and 25 deletions

View file

@ -4,11 +4,35 @@ using Google.Protobuf.WellKnownTypes;
using System.Linq;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Collections.Immutable;
public static class Program
{
class DynamicResourceProviderServicer : ResourceProvider.ResourceProviderBase
{
private static (Pulumi.DynamicResourceProvider, ImmutableDictionary<string, object?>) GetProvider(ImmutableDictionary<string, object?> properties)
{
if (!properties.TryGetValue("__provider", out var providerValue))
{
throw new RpcException(new Status(StatusCode.Unknown, "Dynamic resource had no '__provider' property"));
}
if(!(providerValue is string providerString))
{
throw new RpcException(new Status(StatusCode.Unknown, "Dynamic resource '__provider' property was not a string"));
}
var pickler = new Ibasa.Pikala.Pickler();
var memoryStream = new System.IO.MemoryStream(System.Convert.FromBase64String(providerString));
var provider = pickler.Deserialize(memoryStream) as Pulumi.DynamicResourceProvider;
if (provider == null)
{
throw new RpcException(new Status(StatusCode.Unknown, "Dynamic resource could not deserialise provider implementation"));
}
return (provider , properties.Remove("__provider"));
}
public override Task<CheckResponse> CheckConfig(CheckRequest request, ServerCallContext context)
{
throw new RpcException(new Status(StatusCode.Unimplemented, "CheckConfig is not implemented by the dynamic provider"));
@ -48,14 +72,19 @@ public static class Program
return Task.FromResult(new Empty());
}
public override Task<CreateResponse> Create(CreateRequest request, ServerCallContext context)
public override async Task<CreateResponse> Create(CreateRequest request, ServerCallContext context)
{
var properties = Pulumi.Serialization.Rpc.DeserialiseProperties(request.Properties);
var (provider, inputs) = GetProvider(properties);
var (id, outputs) = await provider.Create(inputs);
var response = new CreateResponse();
response.Id = "some_id";
var result = new Struct();
result.Fields.Add("val", Value.ForString("AQIDBAUG"));
response.Properties = result;
return Task.FromResult(response);
response.Id = id;
response.Properties = Pulumi.Serialization.Rpc.SerialiseProperties(outputs);
// Readd provider
response.Properties.Fields.Add("__provider", request.Properties.Fields["__provider"]);
return response;
}
public override Task<ReadResponse> Read(ReadRequest request, ServerCallContext context)

View file

@ -22,18 +22,10 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Grpc" Version="2.37.0" />
<PackageReference Include="Grpc.Tools" Version="2.37.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="3.1.16" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
<PackageReference Include="OneOf" Version="2.1.151" />
<PackageReference Include="Pulumi.Protobuf" Version="3.13.0" />
<PackageReference Include="semver" Version="2.0.6" />
<PackageReference Include="Serilog.Extensions.Logging" Version="3.0.1" />
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
</ItemGroup>
<ItemGroup>

View file

@ -112,7 +112,7 @@ namespace Pulumi
public SerializationResult ToSerializationResult()
=> new SerializationResult(
Serializer.CreateStruct(PropertyValues),
Serializer.CreateStruct(PropertyValues!),
PropertyToDependentResources);
}
}

View file

@ -2,12 +2,14 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading.Tasks;
namespace Pulumi
{
public abstract class DynamicResourceProvider
{
public virtual (string, IDictionary<string, object?>) Create(IDictionary<string, object?> properties)
public virtual Task<(string, IDictionary<string, object?>)> Create(ImmutableDictionary<string, object?> properties)
{
throw new NotImplementedException();
}

View file

@ -100,7 +100,7 @@ namespace Pulumi.Serialization
});
public static OutputData<object?> Deserialize(Value value)
=> DeserializeCore(value,
=> DeserializeCore(value,
v => v.KindCase switch
{
Value.KindOneofCase.NumberValue => DeserializerDouble(v),

View file

@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using Google.Protobuf.WellKnownTypes;
namespace Pulumi.Serialization
{
public static class Rpc {
public static ImmutableDictionary<string, object?> DeserialiseProperties(Struct properties)
{
var output = Deserializer.Deserialize(Value.ForStruct(properties));
if (!output.IsKnown || !output.IsSecret)
{
throw new Exception("Deserialize of a Struct should always be known and not secret!");
}
var result = output.Value as ImmutableDictionary<string, object?>;
if (result == null)
{
throw new Exception("Deserialize of a Struct should always return an ImmutableDictionary!");
}
return result;
}
public static Struct SerialiseProperties(IDictionary<string, object?> properties)
{
var dictionary = ImmutableDictionary.CreateRange(properties);
return Serializer.CreateStruct(dictionary);
}
}
}

View file

@ -381,7 +381,7 @@ $"Tasks are not allowed inside ResourceArgs. Please wrap your Task in an Output:
bool b => Value.ForBool(b),
string s => Value.ForString(s),
ImmutableArray<object> list => Value.ForList(list.Select(CreateValue).ToArray()),
ImmutableDictionary<string, object> dict => Value.ForStruct(CreateStruct(dict)),
ImmutableDictionary<string, object?> dict => Value.ForStruct(CreateStruct(dict)),
_ => throw new InvalidOperationException("Unsupported value when converting to protobuf: " + value.GetType().FullName),
};
@ -410,7 +410,7 @@ $"Tasks are not allowed inside ResourceArgs. Please wrap your Task in an Output:
/// Given a <see cref="ImmutableDictionary{TKey, TValue}"/> produced by <see cref="SerializeAsync"/>,
/// produces the equivalent <see cref="Struct"/> that can be passed to the Pulumi engine.
/// </summary>
public static Struct CreateStruct(ImmutableDictionary<string, object> serializedDictionary)
public static Struct CreateStruct(ImmutableDictionary<string, object?> serializedDictionary)
{
var result = new Struct();
foreach (var key in serializedDictionary.Keys.OrderBy(k => k))

View file

@ -47,7 +47,7 @@ namespace Pulumi.Testing
}
return new InvokeResponse { Return = await SerializeAsync(registeredResource).ConfigureAwait(false) };
}
var result = await _mocks.CallAsync(new MockCallArgs
{
Token = request.Tok,
@ -183,13 +183,13 @@ namespace Pulumi.Testing
return builder.ToImmutable();
}
private async Task<ImmutableDictionary<string, object>> SerializeToDictionary(object o)
private async Task<ImmutableDictionary<string, object?>> SerializeToDictionary(object o)
{
if (o is IDictionary<string, object> d)
if (o is IDictionary<string, object?> d)
{
o = d.ToImmutableDictionary();
}
return await _serializer.SerializeAsync("", o, true).ConfigureAwait(false) as ImmutableDictionary<string, object>
return await _serializer.SerializeAsync("", o, true).ConfigureAwait(false) as ImmutableDictionary<string, object?>
?? throw new InvalidOperationException($"{o.GetType().FullName} is not a supported argument type");
}

View file

@ -1,12 +1,13 @@
// Copyright 2016-2021, Pulumi Corporation. All rights reserved.
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading.Tasks;
using Pulumi;
public sealed class RandomResourceProvider : DynamicResourceProvider
{
public override (string, IDictionary<string, object>) Create(IDictionary<string, object> properties)
public override async Task<(string, IDictionary<string, object>)> Create(ImmutableDictionary<string, object> properties)
{
var random = new System.Random();
var buffer = new byte[15];
@ -17,7 +18,7 @@ public sealed class RandomResourceProvider : DynamicResourceProvider
}
}
public sealed class RandomArgs : ResourceArgs
public sealed class RandomArgs : DynamicResourceArgs
{
[Input("val")]
public Input<string> Val { get; set; }