Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exclude resource refs from property dependencies for packaged components #488

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions sdk/Pulumi.Tests/Serialization/ResourceRefPropertyTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,42 @@ public async Task SerializeCustomResourceDownlevel(bool isPreview)
Assert.Equal(id, v);
}

[Theory]
[InlineData(true, true)]
[InlineData(true, false)]
[InlineData(false, true)]
[InlineData(false, false)]
public async Task SerializeCustomResourceDependencies(bool isPreview, bool excludeFromDependencies)
{
var resources = await RunAsync<MyStack>(isPreview);
var res = resources.OfType<MyCustomResource>().Single();

async Task Test<T>(T value)
{
var serializer = new Serializer(excessiveDebugOutput: false);
Serializer.CreateValue(await serializer.SerializeAsync("", value, true,
excludeResourceReferencesFromDependencies: excludeFromDependencies));

if (excludeFromDependencies)
{
Assert.Empty(serializer.DependentResources);
}
else
{
Assert.Equal(new HashSet<Resource> { res }, serializer.DependentResources);
}
}

// Single resource.
await Test(res);

// Resource in list.
await Test(new List<Resource> { res });

// Resource in dictionary.
await Test(new Dictionary<string, Resource> { { "resource", res } });
}

public class DeserializeCustomResourceStack : Stack
{
[Output("values")]
Expand Down
3 changes: 2 additions & 1 deletion sdk/Pulumi/Deployment/Deployment_Call.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ private async Task<OutputData<T>> CallAsync<T>(
$"call:{token}",
argsDict, _ => true,
keepResources: true,
keepOutputValues: await MonitorSupportsOutputValues().ConfigureAwait(false)).ConfigureAwait(false);
keepOutputValues: await MonitorSupportsOutputValues().ConfigureAwait(false),
excludeResourceReferencesFromDependencies: true).ConfigureAwait(false);
Log.Debug($"Call RPC prepared: token={token}" +
(_excessiveDebugOutput ? $", obj={serialized}" : ""));

Expand Down
12 changes: 10 additions & 2 deletions sdk/Pulumi/Deployment/Deployment_Prepare.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,20 @@ private async Task<PrepareResult> PrepareResourceAsync(
// the Resources pointed to by any Dependency objects we encounter, adding them to 'propertyDependencies'.
LogExcessive($"Serializing properties: t={type}, name={name}, custom={custom}, remote={remote}");
var dictionary = await args.ToDictionaryAsync().ConfigureAwait(false);
var keepResources = await MonitorSupportsResourceReferences().ConfigureAwait(false);
var keepOutputValues = remote && await MonitorSupportsOutputValues().ConfigureAwait(false);
// When remote is true (and the monitor supports resource references), exclude resource references
// from `propertyToDirectDependencies`. This way, component providers creating outputs for component
// inputs based on "propertyDependencies" won't create outputs for properties that only contain
// resource references.
var excludeResourceReferencesFromDependencies = remote && keepResources;
var (serializedProps, propertyToDirectDependencies) =
await SerializeResourcePropertiesAsync(
label,
dictionary,
await this.MonitorSupportsResourceReferences().ConfigureAwait(false),
keepOutputValues: remote && await MonitorSupportsOutputValues().ConfigureAwait(false)).ConfigureAwait(false);
keepResources,
keepOutputValues,
excludeResourceReferencesFromDependencies).ConfigureAwait(false);
LogExcessive($"Serialized properties: t={type}, name={name}, custom={custom}, remote={remote}");

// Wait for the parent to complete.
Expand Down
28 changes: 20 additions & 8 deletions sdk/Pulumi/Deployment/Deployment_Serialization.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,22 @@ public partial class Deployment
/// to registerResource.
/// </summary>
private static Task<SerializationResult> SerializeResourcePropertiesAsync(
string label, IDictionary<string, object?> args, bool keepResources, bool keepOutputValues)
string label, IDictionary<string, object?> args, bool keepResources, bool keepOutputValues,
bool excludeResourceReferencesFromDependencies = false)
{
return SerializeFilteredPropertiesAsync(
label, args,
key => key != Constants.IdPropertyName && key != Constants.UrnPropertyName,
keepResources, keepOutputValues: keepOutputValues);
keepResources, keepOutputValues, excludeResourceReferencesFromDependencies);
}

private static async Task<Struct> SerializeAllPropertiesAsync(
string label, IDictionary<string, object?> args, bool keepResources, bool keepOutputValues = false)
string label, IDictionary<string, object?> args, bool keepResources, bool keepOutputValues = false,
bool excludeResourceReferencesFromDependencies = false)
{
var result = await SerializeFilteredPropertiesAsync(
label, args, _ => true,
keepResources, keepOutputValues).ConfigureAwait(false);
keepResources, keepOutputValues, excludeResourceReferencesFromDependencies).ConfigureAwait(false);
return result.Serialized;
}

Expand All @@ -52,10 +54,18 @@ private static async Task<Struct> SerializeAllPropertiesAsync(
/// responsibility to ensure that the monitor supports the OutputValues
/// feature.
/// </param>
/// <param name="excludeResourceReferencesFromDependencies">
/// Specifies if we should exclude resource references from the resulting
/// <see cref="SerializationResult.PropertyToDependentResources"/>. This is useful for remote
/// components (i.e. multi-lang components, or MLCs) where we want property dependencies to be
/// empty for a property that only contains resource references.
/// </param>
private static async Task<SerializationResult> SerializeFilteredPropertiesAsync(
string label, IDictionary<string, object?> args, Predicate<string> acceptKey, bool keepResources, bool keepOutputValues)
string label, IDictionary<string, object?> args, Predicate<string> acceptKey, bool keepResources, bool keepOutputValues,
bool excludeResourceReferencesFromDependencies = false)
{
var result = await SerializeFilteredPropertiesRawAsync(label, args, acceptKey, keepResources, keepOutputValues);
var result = await SerializeFilteredPropertiesRawAsync(label, args, acceptKey, keepResources, keepOutputValues,
excludeResourceReferencesFromDependencies);
return result.ToSerializationResult();
}

Expand All @@ -64,7 +74,8 @@ private static async Task<SerializationResult> SerializeFilteredPropertiesAsync(
/// last step of encoding the value into a Protobuf form.
/// </summary>
private static async Task<RawSerializationResult> SerializeFilteredPropertiesRawAsync(
string label, IDictionary<string, object?> args, Predicate<string> acceptKey, bool keepResources, bool keepOutputValues)
string label, IDictionary<string, object?> args, Predicate<string> acceptKey, bool keepResources, bool keepOutputValues,
bool excludeResourceReferencesFromDependencies = false)
{
var propertyToDependentResources = ImmutableDictionary.CreateBuilder<string, HashSet<Resource>>();
var result = ImmutableDictionary.CreateBuilder<string, object>();
Expand All @@ -75,7 +86,8 @@ private static async Task<RawSerializationResult> SerializeFilteredPropertiesRaw
{
// We treat properties with null values as if they do not exist.
var serializer = new Serializer(_excessiveDebugOutput);
var v = await serializer.SerializeAsync($"{label}.{key}", val, keepResources, keepOutputValues).ConfigureAwait(false);
var v = await serializer.SerializeAsync($"{label}.{key}", val, keepResources, keepOutputValues,
excludeResourceReferencesFromDependencies).ConfigureAwait(false);
if (v != null)
{
result[key] = v;
Expand Down
Loading
Loading