Skip to content

[dotnet] NativeAoT Compatibility for Pulumi.Automation #687

Description

@ThaDaVos

What happened?

I love the Automation API as it allows one to include it inside a program - but it seems NativeAoT is not completely supported yet as the JSON is still using the Reflection API instead of the Source Generated one:

Unhandled exception. System.InvalidOperationException: Reflection-based serialization has been disabled for this application. Either use the source generator APIs or explicitly configure the 'JsonSerializerOptions.TypeInfoResolver' property.
   at System.Text.Json.ThrowHelper.ThrowInvalidOperationException_JsonSerializerIsReflectionDisabled()
   at System.Text.Json.JsonSerializerOptions.ConfigureForJsonSerializer()
   at System.Text.Json.JsonSerializer.GetTypeInfo(JsonSerializerOptions options, Type inputType)
   at System.Text.Json.JsonSerializer.GetTypeInfo[T](JsonSerializerOptions options)
   at System.Text.Json.JsonSerializer.Deserialize[TValue](String json, JsonSerializerOptions options)
   at Pulumi.Automation.WorkspaceStack.GetHistoryAsync(HistoryOptions options, CancellationToken cancellationToken)
   at Pulumi.Automation.WorkspaceStack.GetInfoAsync(Nullable`1 showSecrets, CancellationToken cancellationToken)
   at Pulumi.Automation.WorkspaceStack.RefreshAsync(RefreshOptions options, CancellationToken cancellationToken)

The reason for above exception is due to my Directory.Build.Props file I use for most of my projects, this one includes the following line to prevent me for accidentally using it:

...
<JsonSerializerIsReflectionEnabledByDefault>false</JsonSerializerIsReflectionEnabledByDefault>
...

Example

Below program:

using Pulumi.Automation;

const string projectName = "SmartHome";
const string stackName = "SmartHome";

bool destroy = args.Length != 0 && args[0] == "destroy";
bool preview = args.Length != 0 && args[0] == "preview";

IDictionary<string, object?> Configuration()
{
    return new Dictionary<string, object?>
    {
        ["outputKey"] = "outputValue"
    };
}

PulumiFn program = PulumiFn.Create(Configuration);

InlineProgramArgs stackArgs = new InlineProgramArgs(
    projectName: projectName,
    stackName: stackName,
    program: program
);

WorkspaceStack stack = await LocalWorkspace.CreateOrSelectStackAsync(stackArgs);

Console.WriteLine("successfully initialized stack");

// for inline programs, we must manage plugins ourselves
Console.WriteLine("installing plugins...");
// await stack.Workspace.InstallPluginAsync("aws", "v5.41.0");
Console.WriteLine("plugins installed");

// set stack configuration specifying the region to deploy
Console.WriteLine("setting up config...");
// await stack.SetConfigAsync("aws:region", new ConfigValue("us-west-2"));
Console.WriteLine("config set");

Console.WriteLine("refreshing stack...");
await stack.RefreshAsync(new RefreshOptions { OnStandardOutput = Console.WriteLine });
Console.WriteLine("refresh complete");

if (destroy)
{
    Console.WriteLine("destroying stack...");
    await stack.DestroyAsync(new DestroyOptions { OnStandardOutput = Console.WriteLine });
    Console.WriteLine("stack destroy complete");
}
else if (preview)
{
    Console.WriteLine("previewing stack...");
    await stack.PreviewAsync(new PreviewOptions { OnStandardOutput = Console.WriteLine });
    Console.WriteLine("stack preview complete");
}
else
{
    Console.WriteLine("updating stack...");
    UpResult result = await stack.UpAsync(new UpOptions { OnStandardOutput = Console.WriteLine });

    if (result.Summary.ResourceChanges != null)
    {
        Console.WriteLine("update summary:");
        foreach (var change in result.Summary.ResourceChanges)
        {
            Console.WriteLine($"    {change.Key}: {change.Value}");
        }
    }
}

With the following Directory.Build.props file in the root of the project:

<Project>
    <PropertyGroup>
        <AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
        <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
        <ArtifactsPath>$(MSBuildThisFileDirectory)\Out</ArtifactsPath>
        <CompilerGeneratedFilesOutputPath>$(MSBuildThisFileDirectory)\Out\.generated</CompilerGeneratedFilesOutputPath>
        <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
        <EnableConfigurationBindingGenerator>true</EnableConfigurationBindingGenerator>
        <ImplicitUsings>enable</ImplicitUsings>
        <JsonSerializerIsReflectionEnabledByDefault>false</JsonSerializerIsReflectionEnabledByDefault>
        <LangVersion>preview</LangVersion>
        <Nullable>enable</Nullable>
        <PlatformTarget>x64</PlatformTarget>
        <PublishAot>true</PublishAot>
        <PublishTrimmed>true</PublishTrimmed>
        <RootNamespace>My.IaC.SmartHome</RootNamespace>
        <TargetFramework>net9.0</TargetFramework>
        <TrimMode>link</TrimMode>
        <UseArtifactsOutput>True</UseArtifactsOutput>
    </PropertyGroup>
</Project>

Output of pulumi about

CLI
Version 3.190.0
Go Version go1.25.0
Go Compiler gc

Host
OS Microsoft Windows 11 Pro
Version 10.0.26100 Build 26100
Arch x86_64

Backend
Name pulumi.com
URL https://app.pulumi.com/ThaDaVos
User ThaDaVos
Organizations ThaDaVos, ThaDaVos-org
Token type personal

Pulumi locates its logs in C:\Users\Dylan\AppData\Local\Temp by default
warning: Failed to read project: no Pulumi.yaml project file found (searching upwards from P:\Personal\IaC-SmartHome). If you have not created a project yet, use pulumi new to do so: no project file found
warning: Failed to get information about the current stack: no Pulumi.yaml project file found (searching upwards from P:\Personal\IaC-SmartHome). If you have not created a project yet, use pulumi new to do so: no project file found

Additional context

This project is aimed at the use of the Automation API - so no pulumi.yaml file

Contributing

Vote on this issue by adding a 👍 reaction.
To contribute a fix for this issue, leave a comment (and link to your pull request, if you've opened one already).

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions