Pass dependency information to the engine
Dependency information can come from one of two places, an explicit set of resources that you depend on (via the ResourceOptions struct) and dependencies we infer from output tracking.
This commit is contained in:
parent
66ef108516
commit
9de9ad2f97
|
@ -23,7 +23,8 @@ namespace Pulumi {
|
|||
} else if (resp.IsFaulted) {
|
||||
m_IdCompletionSoruce.SetException(resp.Exception);
|
||||
} else {
|
||||
m_IdCompletionSoruce.SetResult(new OutputState<string>(resp.Result.Id, !string.IsNullOrEmpty(resp.Result.Id)));
|
||||
Serilog.Log.Debug("Setting id to {id} for {urn} with dependency {this}", resp.Result.Id, resp.Result.Urn, this);
|
||||
m_IdCompletionSoruce.SetResult(new OutputState<string>(resp.Result.Id, !string.IsNullOrEmpty(resp.Result.Id), this));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,11 +35,14 @@ namespace Pulumi {
|
|||
|
||||
public async Task<OutputState<object>> GetValueAsOutputStateAsync() {
|
||||
if (m_task != null) {
|
||||
return new OutputState<object>(await m_task, true);
|
||||
return new OutputState<object>(await m_task, true, Array.Empty<Resource>());
|
||||
} else if (m_output != null) {
|
||||
return await ((IOutput)m_output).GetOutputStateAsync();
|
||||
} else {
|
||||
return new OutputState<object>(m_rawValue, true);
|
||||
// If the underlying value is a resource, ensure we flow the resource as a dependency in the synthetic output state.
|
||||
// TODO(ellismg): Doing this here feels wrong for some reason.
|
||||
Resource r = m_rawValue as Resource;
|
||||
return new OutputState<object>(m_rawValue, true, r != null ? new Resource[] { r } : Array.Empty<Resource>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,9 +8,13 @@ namespace Pulumi {
|
|||
public T Value { get; private set; }
|
||||
public bool IsKnown { get; private set; }
|
||||
|
||||
public OutputState(T value, bool isKnown) {
|
||||
public Resource[] DependsOn { get; private set; }
|
||||
|
||||
public OutputState(T value, bool isKnown, params Resource[] dependsOn) {
|
||||
Serilog.Log.Debug("Creating new OutputState {value} {isKnown} {dependsOn}", value, isKnown, dependsOn);
|
||||
Value = value;
|
||||
IsKnown = isKnown;
|
||||
DependsOn = dependsOn;
|
||||
}
|
||||
}
|
||||
interface IOutput {
|
||||
|
@ -26,7 +30,7 @@ namespace Pulumi {
|
|||
|
||||
async Task<OutputState<object>> IOutput.GetOutputStateAsync() {
|
||||
var resolvedState = await m_stateTask;
|
||||
return new OutputState<object>(resolvedState.Value, resolvedState.IsKnown);
|
||||
return new OutputState<object>(resolvedState.Value, resolvedState.IsKnown, resolvedState.DependsOn);
|
||||
}
|
||||
|
||||
public void Apply(Action<T> fn) {
|
||||
|
@ -38,7 +42,8 @@ namespace Pulumi {
|
|||
public Output<U> Apply<U>(Func<T, U> fn) {
|
||||
return new Output<U>(this.m_stateTask.ContinueWith(x => new OutputState<U>(
|
||||
x.Result.IsKnown ? fn(x.Result.Value) : default(U),
|
||||
x.Result.IsKnown)));
|
||||
x.Result.IsKnown,
|
||||
x.Result.DependsOn)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using Google.Protobuf.Collections;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using Pulumirpc;
|
||||
using System;
|
||||
|
@ -25,7 +26,7 @@ namespace Pulumi
|
|||
} else if (resp.IsFaulted) {
|
||||
m_UrnCompletionSource.SetException(resp.Exception);
|
||||
} else {
|
||||
m_UrnCompletionSource.SetResult(new OutputState<string>(resp.Result.Urn, resp.Result.Urn != null));
|
||||
m_UrnCompletionSource.SetResult(new OutputState<string>(resp.Result.Urn, resp.Result.Urn != null, this));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,19 +53,45 @@ namespace Pulumi
|
|||
parentUrn = urnOutput.GetOutputStateAsync().ContinueWith(x => (string)x.Result.Value);
|
||||
}
|
||||
|
||||
// Compute the set of dependencies this resource has. This is the union of resources the object explicitly depends on
|
||||
// with the set of dependencies that any Output that is used as in Input has.
|
||||
HashSet<string> dependsOnUrns = new HashSet<string>(StringComparer.Ordinal);
|
||||
|
||||
// Explicit dependencies.
|
||||
if (options.DependsOn != null) {
|
||||
foreach (Resource r in options.DependsOn) {
|
||||
dependsOnUrns.Add((string)(await ((IOutput)r.Urn).GetOutputStateAsync()).Value);
|
||||
}
|
||||
}
|
||||
|
||||
// Add any dependeices from any outputs that happend to be used as inputs.
|
||||
if (properties != null) {
|
||||
foreach (object o in properties.Values) {
|
||||
IInput input = o as IInput;
|
||||
if (input != null) {
|
||||
foreach (Resource r in (await input.GetValueAsOutputStateAsync()).DependsOn) {
|
||||
dependsOnUrns.Add((string)(await ((IOutput)r.Urn).GetOutputStateAsync()).Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach(string urn in dependsOnUrns) {
|
||||
Serilog.Log.Debug("Dependency: {urn}", urn);
|
||||
}
|
||||
|
||||
// Kick off the registration, and when it completes, call the OnResourceRegistrationCompete method which will resolve all the tasks to their values. The fact that we don't
|
||||
// await here is by design. This method is called by child classes in their constructors, where were do not want to block.
|
||||
#pragma warning disable 4014
|
||||
Runtime.Monitor.RegisterResourceAsync(
|
||||
new RegisterResourceRequest()
|
||||
{
|
||||
Type = type,
|
||||
Name = name,
|
||||
Custom = custom,
|
||||
Protect = false,
|
||||
Object = await SerializeProperties(properties),
|
||||
Parent = await parentUrn
|
||||
}).ResponseAsync.ContinueWith((x) => OnResourceRegistrationComplete(x));
|
||||
RegisterResourceRequest request = new RegisterResourceRequest();
|
||||
request.Type = type;
|
||||
request.Name = name;
|
||||
request.Custom = custom;
|
||||
request.Protect = options.Protect;
|
||||
request.Object = await SerializeProperties(properties);
|
||||
request.Parent = await parentUrn;
|
||||
request.Dependencies.AddRange(dependsOnUrns);
|
||||
Runtime.Monitor.RegisterResourceAsync(request).ResponseAsync.ContinueWith((x) => OnResourceRegistrationComplete(x));
|
||||
#pragma warning restore 4014
|
||||
}
|
||||
|
||||
|
|
|
@ -34,12 +34,8 @@ namespace AWS.S3 {
|
|||
|
||||
var fields = resp.Result.Object.Fields;
|
||||
|
||||
foreach (var kvp in fields) {
|
||||
Serilog.Log.Debug("got property {key}", kvp.Key);
|
||||
}
|
||||
|
||||
bool isKnown = fields.ContainsKey("bucketDomainName");
|
||||
m_BucketDomainNameCompletionSource.SetResult(new OutputState<string>(isKnown ? fields["bucketDomainName"].StringValue : default(string), isKnown));
|
||||
m_BucketDomainNameCompletionSource.SetResult(new OutputState<string>(isKnown ? fields["bucketDomainName"].StringValue : default(string), isKnown, this));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue