private async Task <T> InvokeAsync <T>( string token, InvokeArgs args, InvokeOptions?options, bool convertResult) { var result = await InvokeRawAsync(token, args, options); if (!convertResult) { return(default !);
private async Task <OutputData <T> > RawInvoke <T>(string token, InvokeArgs args, InvokeOptions?options) { // This method backs all `Fn.Invoke()` calls that generate // `Output<T>` and may include `Input<T>` values in the // `args`. It needs to decide which control-flow tracking // features are supported in the SDK and which ones in the // provider implementing the invoke logic. // // Current choices are: // // - any resource dependency found by a recursive // traversal of `args` that awaits and inspects every // `Input<T>` will always be propagated into the // `Output<T>`; the provider cannot "swallow" // dependencies // // - the provider is responsible for deciding whether the // `Output<T>` is secret and known, and may add // additional dependencies // // This means that presence of secrets or unknowns in the // `args` does not guarantee the result is secret or // unknown, which differs from Pulumi SDKs that choose to // implement these invokes via `Apply` (currently Go and // Python). // // Differences from `Call`: the `Invoke` gRPC protocol // does not yet support passing or returning out-of-band // dependencies to the provider, and in-band `Resource` // value support is subject to feature negotiation (see // `MonitorSupportsResourceReferences`). So `Call` makes // the provider fully responsible for depdendency // tracking, which is a good future direction also for // `Invoke`. var result = await InvokeRawAsync(token, args, options).ConfigureAwait(false); var data = Converter.ConvertValue <T>($"{token} result", new Value { StructValue = result.Serialized }); var resources = ImmutableHashSet.CreateRange( result.PropertyToDependentResources.Values.SelectMany(r => r) .Union(data.Resources)); return(new OutputData <T>(resources: resources, value: data.Value, isKnown: data.IsKnown, isSecret: data.IsSecret)); }
private async Task <T> InvokeAsync <T>( string token, InvokeArgs args, InvokeOptions?options, bool convertResult) { var label = $"Invoking function: token={token} asynchronously"; Log.Debug(label); // Be resilient to misbehaving callers. args ??= InvokeArgs.Empty; // Wait for all values to be available, and then perform the RPC. var argsDict = await args.ToDictionaryAsync().ConfigureAwait(false); var serialized = await SerializeAllPropertiesAsync( $"invoke:{token}", argsDict, await this.MonitorSupportsResourceReferences().ConfigureAwait(false)).ConfigureAwait(false); Log.Debug($"Invoke RPC prepared: token={token}" + (_excessiveDebugOutput ? $", obj={serialized}" : "")); var provider = await ProviderResource.RegisterAsync(GetProvider(token, options)).ConfigureAwait(false); var result = await this.Monitor.InvokeAsync(new InvokeRequest { Tok = token, Provider = provider ?? "", Version = options?.Version ?? "", Args = serialized, }); if (result.Failures.Count > 0) { var reasons = ""; foreach (var reason in result.Failures) { if (reasons != "") { reasons += "; "; } reasons += $"{reason.Reason} ({reason.Property})"; } throw new InvokeException($"Invoke of '{token}' failed: {reasons}"); } if (!convertResult) { return(default !);
private async Task <OutputData <T> > RawInvoke <T>(string token, InvokeArgs args, InvokeOptions?options) { // This method backs all `Fn.Invoke()` calls that generate // `Output<T>` and may include `Input<T>` values in the // `args`. It needs to decide which control-flow tracking // features are supported in the SDK and which ones in the // provider implementing the invoke logic. // // Current choices are: // // - any resource dependency found by a recursive // traversal of `args` that awaits and inspects every // `Input<T>` will always be propagated into the // `Output<T>`; the provider cannot "swallow" // dependencies // // - the provider is responsible for deciding whether the // `Output<T>` is secret and known, and may add // additional dependencies // // This means that presence of secrets or unknowns in the // `args` does not guarantee the result is secret or // unknown, which differs from Pulumi SDKs that choose to // implement these invokes via `Apply` (currently Go and // Python). // // Differences from `Call`: the `Invoke` gRPC protocol // does not yet support passing or returning out-of-band // dependencies to the provider, and in-band `Resource` // value support is subject to feature negotiation (see // `MonitorSupportsResourceReferences`). So `Call` makes // the provider fully responsible for depdendency // tracking, which is a good future direction also for // `Invoke`. var keepResources = await this.MonitorSupportsResourceReferences().ConfigureAwait(false); var serializedArgs = await SerializeInvokeArgs(token, args, keepResources); // Short-circuit actually invoking if `Unknowns` are // present in `args`, otherwise preview can break. if (Serializer.ContainsUnknowns(serializedArgs.PropertyValues)) { return(new OutputData <T>(resources: ImmutableHashSet <Resource> .Empty, value: default !,
Task <T> IDeployment.InvokeAsync <T>(string token, InvokeArgs args, InvokeOptions?options) => InvokeAsync <T>(token, args, options, convertResult: true);
Task IDeployment.InvokeAsync(string token, InvokeArgs args, InvokeOptions?options) => InvokeAsync <object>(token, args, options, convertResult: false);
Output <T> IDeployment.Invoke <T>(string token, InvokeArgs args, InvokeOptions?options) => new Output <T>(RawInvoke <T>(token, args, options));
/// <summary> /// Same as <see cref="InvokeAsync{T}(string, InvokeArgs, InvokeOptions)"/>, however the /// return value is ignored. /// </summary> public Task InvokeAsync(string token, InvokeArgs args, InvokeOptions?options = null) => _deployment.InvokeAsync(token, args, options);
/// <summary> /// Dynamically invokes the function '<paramref name="token"/>', which is offered by a /// provider plugin. /// <para/> /// The result of <see cref="Invoke"/> will be a <see cref="Output"/> resolved to the /// result value of the provider plugin. /// <para/> /// Similar to the earlier <see cref="InvokeAsync"/>, but supports passing input values /// and returns an Output value. /// <para/> /// The <paramref name="args"/> inputs can be a bag of computed values(including, `T`s, /// <see cref="Task{TResult}"/>s, <see cref="Output{T}"/>s etc.). /// </summary> public Output <T> Invoke <T>(string token, InvokeArgs args, InvokeOptions?options = null) => _deployment.Invoke <T>(token, args, options);