From e7915b4f69d7c2d59d7c0f837e1d56a3010cc01c Mon Sep 17 00:00:00 2001 From: Thomas Gummerer Date: Thu, 3 Oct 2024 16:58:43 +0200 Subject: [PATCH] WIP: allow dotnet to emit better errors for component construct Introduce a new InputPropertiesError that allows users to return more error details from a component construct. --- .../dotnet/Component.cs | 50 ++++ .../dotnet/Program.cs | 19 ++ .../dotnet/ProviderConstructFailure.csproj | 16 ++ .../dotnet/Pulumi.yaml | 7 + .../testcomponent-dotnet/Component.cs | 22 ++ .../testcomponent-dotnet/Program.cs | 9 + .../testcomponent-dotnet/PulumiPlugin.yaml | 1 + .../testcomponent-dotnet/TestProvider.csproj | 13 + .../testcomponent-dotnet/TestProviderImpl.cs | 20 ++ integration_tests/integration_dotnet_test.go | 37 +++ proto/pulumi/errors.proto | 13 + proto/pulumi/language.proto | 14 +- proto/pulumi/provider.proto | 20 ++ proto/pulumi/testing/language.proto | 5 + .../Exceptions/InputPropertiesException.cs | 51 ++++ sdk/Pulumi/Pulumi.csproj | 12 +- sdk/Pulumi/Pulumi.xml | 256 +++++++++++++++--- 17 files changed, 511 insertions(+), 54 deletions(-) create mode 100644 integration_tests/construct_component_failures/dotnet/Component.cs create mode 100644 integration_tests/construct_component_failures/dotnet/Program.cs create mode 100644 integration_tests/construct_component_failures/dotnet/ProviderConstructFailure.csproj create mode 100644 integration_tests/construct_component_failures/dotnet/Pulumi.yaml create mode 100644 integration_tests/construct_component_failures/testcomponent-dotnet/Component.cs create mode 100644 integration_tests/construct_component_failures/testcomponent-dotnet/Program.cs create mode 100644 integration_tests/construct_component_failures/testcomponent-dotnet/PulumiPlugin.yaml create mode 100644 integration_tests/construct_component_failures/testcomponent-dotnet/TestProvider.csproj create mode 100644 integration_tests/construct_component_failures/testcomponent-dotnet/TestProviderImpl.cs create mode 100644 sdk/Pulumi/Exceptions/InputPropertiesException.cs diff --git a/integration_tests/construct_component_failures/dotnet/Component.cs b/integration_tests/construct_component_failures/dotnet/Component.cs new file mode 100644 index 00000000..3b344549 --- /dev/null +++ b/integration_tests/construct_component_failures/dotnet/Component.cs @@ -0,0 +1,50 @@ +using Pulumi; + +class Component : Pulumi.ComponentResource +{ + public Component(string name, ComponentArgs args, ComponentResourceOptions? opts = null) + : base("test:index:Test", name, args, opts, remote: true) + { + } + + [Output("passwordResult")] + public Output PasswordResult { get; private set; } = default!; + + [Output("complexResult")] + public Output ComplexResult { get; set; } = default!; +} + +class ComponentArgs : ResourceArgs +{ + [Input("passwordLength")] + public Input PasswordLength { get; set; } = null!; + + [Input("complex")] + public Input Complex { get; set; } = null!; +} + +public sealed class ComplexTypeArgs : global::Pulumi.ResourceArgs +{ + [Input("name", required: true)] + public string Name { get; set; } = null!; + + [Input("intValue", required: true)] + public int IntValue { get; set; } +} + +[OutputType] +public sealed class ComplexType +{ + [Output("name")] + public string Name { get; set; } + + [Output("intValue")] + public int IntValue { get; set; } + + [OutputConstructor] + public ComplexType(string name, int intValue) + { + Name = name; + IntValue = intValue; + } +} diff --git a/integration_tests/construct_component_failures/dotnet/Program.cs b/integration_tests/construct_component_failures/dotnet/Program.cs new file mode 100644 index 00000000..4ca36fad --- /dev/null +++ b/integration_tests/construct_component_failures/dotnet/Program.cs @@ -0,0 +1,19 @@ +using System.Threading.Tasks; +using FluentAssertions; +using Pulumi; +using Pulumi.Utilities; + +using Pulumi.IntegrationTests.Utils; + +class Program +{ + static async Task Main(string[] args) + { + var returnCode = await Deployment.RunAsync(async () => + { + var component10 = new Component("component10", new ComponentArgs()); + }); + return returnCode; + } + +} diff --git a/integration_tests/construct_component_failures/dotnet/ProviderConstructFailure.csproj b/integration_tests/construct_component_failures/dotnet/ProviderConstructFailure.csproj new file mode 100644 index 00000000..e43e29c1 --- /dev/null +++ b/integration_tests/construct_component_failures/dotnet/ProviderConstructFailure.csproj @@ -0,0 +1,16 @@ + + + + Exe + net6.0 + enable + + + + + + + + + + diff --git a/integration_tests/construct_component_failures/dotnet/Pulumi.yaml b/integration_tests/construct_component_failures/dotnet/Pulumi.yaml new file mode 100644 index 00000000..03af2b48 --- /dev/null +++ b/integration_tests/construct_component_failures/dotnet/Pulumi.yaml @@ -0,0 +1,7 @@ +name: provider_construct +runtime: dotnet + +plugins: + providers: + - name: test + path: ../testcomponent-dotnet diff --git a/integration_tests/construct_component_failures/testcomponent-dotnet/Component.cs b/integration_tests/construct_component_failures/testcomponent-dotnet/Component.cs new file mode 100644 index 00000000..f001c4d8 --- /dev/null +++ b/integration_tests/construct_component_failures/testcomponent-dotnet/Component.cs @@ -0,0 +1,22 @@ +using System; +using System.Text; +using System.Threading.Tasks; +using Pulumi; + +class ComponentArgs : ResourceArgs +{ +} + +class Component : ComponentResource +{ + public Component(string name, ComponentArgs args, ComponentResourceOptions? opts = null) + : base("test:index:Test", name, args, opts) + { + throw new InputPropertiesException( + "failing for a reason", + new[] + { + new PropertyError("foo", "the failure reason"), + }); + } +} diff --git a/integration_tests/construct_component_failures/testcomponent-dotnet/Program.cs b/integration_tests/construct_component_failures/testcomponent-dotnet/Program.cs new file mode 100644 index 00000000..21887858 --- /dev/null +++ b/integration_tests/construct_component_failures/testcomponent-dotnet/Program.cs @@ -0,0 +1,9 @@ +using System.Threading; +using System.Threading.Tasks; +using TestProvider; + +class Program +{ + public static Task Main(string []args) => + Pulumi.Experimental.Provider.Provider.Serve(args, "0.0.1", host => new TestProviderImpl(), CancellationToken.None); +} diff --git a/integration_tests/construct_component_failures/testcomponent-dotnet/PulumiPlugin.yaml b/integration_tests/construct_component_failures/testcomponent-dotnet/PulumiPlugin.yaml new file mode 100644 index 00000000..82aad0f3 --- /dev/null +++ b/integration_tests/construct_component_failures/testcomponent-dotnet/PulumiPlugin.yaml @@ -0,0 +1 @@ +runtime: dotnet \ No newline at end of file diff --git a/integration_tests/construct_component_failures/testcomponent-dotnet/TestProvider.csproj b/integration_tests/construct_component_failures/testcomponent-dotnet/TestProvider.csproj new file mode 100644 index 00000000..1fba25bf --- /dev/null +++ b/integration_tests/construct_component_failures/testcomponent-dotnet/TestProvider.csproj @@ -0,0 +1,13 @@ + + + + Exe + net6.0 + enable + pulumi-resource-test + + + + + + \ No newline at end of file diff --git a/integration_tests/construct_component_failures/testcomponent-dotnet/TestProviderImpl.cs b/integration_tests/construct_component_failures/testcomponent-dotnet/TestProviderImpl.cs new file mode 100644 index 00000000..9da2e590 --- /dev/null +++ b/integration_tests/construct_component_failures/testcomponent-dotnet/TestProviderImpl.cs @@ -0,0 +1,20 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Pulumi.Experimental.Provider; +using Pulumi.IntegrationTests.Utils; + +namespace TestProvider; + +public class TestProviderImpl : ComponentResourceProviderBase +{ + public override Task Construct(ConstructRequest request, CancellationToken ct) + { + return request.Type switch + { + "test:index:Test" => Construct(request, + (name, args, options) => Task.FromResult(new Component(name, args, options))), + _ => throw new NotImplementedException() + }; + } +} diff --git a/integration_tests/integration_dotnet_test.go b/integration_tests/integration_dotnet_test.go index 80e2e4ed..68500804 100644 --- a/integration_tests/integration_dotnet_test.go +++ b/integration_tests/integration_dotnet_test.go @@ -15,6 +15,7 @@ package integration_tests import ( + "bytes" "encoding/json" "fmt" "io" @@ -666,3 +667,39 @@ outer: wg.Wait() } + +// Test failures returned from construct. +func TestConstructFailuresDotnet(t *testing.T) { + const testDir = "construct_component_failures" + + tests := []struct { + componentDir string + }{ + { + componentDir: "testcomponent-dotnet", + }, + } + for _, test := range tests { + test := test + t.Run(test.componentDir, func(t *testing.T) { + stderr := &bytes.Buffer{} + expectedError := `error: testcomponent:index:Component resource 'component' has a problem: failing for a reason: + - property foo with value '{bar}' has a problem: the failure reason` + + localProvider := integration.LocalDependency{ + Package: "testcomponent", Path: filepath.Join(testDir, test.componentDir), + } + testDotnetProgram(t, &integration.ProgramTestOptions{ + Dir: filepath.Join(testDir, "dotnet"), + LocalProviders: []integration.LocalDependency{localProvider}, + Quick: true, + Stderr: stderr, + ExpectFailure: true, + ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) { + output := stderr.String() + assert.Contains(t, output, expectedError) + }, + }) + }) + } +} diff --git a/proto/pulumi/errors.proto b/proto/pulumi/errors.proto index 077c4739..a44bf0ae 100644 --- a/proto/pulumi/errors.proto +++ b/proto/pulumi/errors.proto @@ -23,3 +23,16 @@ message ErrorCause { string stackTrace = 2; } +// An error that can be returned from a component provider and includes details of the +// error, which can be multiple properties. +message InputPropertiesError { + // A single invalid input property. + message PropertyError { + // The path to the property that is invalid. + string property_path = 1; + // The reason the property is invalid. + string reason = 2; + } + // The list of invalid input properties. + repeated PropertyError errors = 1; +} diff --git a/proto/pulumi/language.proto b/proto/pulumi/language.proto index 908d5d30..fb21c902 100644 --- a/proto/pulumi/language.proto +++ b/proto/pulumi/language.proto @@ -91,8 +91,8 @@ message AboutResponse { message GetProgramDependenciesRequest { string project = 1 [deprecated = true]; // the project name, the engine always sets this to "deprecated" now. - string pwd = 2 [deprecated = true]; // the program's working directory. - string program = 3 [deprecated = true]; // the path to the program. + string pwd = 2 [deprecated = true]; // the program's working directory. Deprecated, use info.program_directory instead. + string program = 3 [deprecated = true]; // the path to the program. Deprecated, use info.entry_point instead. bool transitiveDependencies = 4; // if transitive dependencies should be included in the result. ProgramInfo info = 5; // the program info to use to calculate dependencies. } @@ -108,8 +108,8 @@ message GetProgramDependenciesResponse { message GetRequiredPluginsRequest { string project = 1 [deprecated = true]; // the project name, the engine always sets this to "deprecated" now. - string pwd = 2 [deprecated = true]; // the program's working directory. - string program = 3 [deprecated = true]; // the path to the program. + string pwd = 2 [deprecated = true]; // the program's working directory. Deprecated, use info.program_directory instead. + string program = 3 [deprecated = true]; // the path to the program. Deprecated, use info.entry_point instead. ProgramInfo info = 4; // the program info to use to calculate plugins. } @@ -122,7 +122,7 @@ message RunRequest { string project = 1; // the project name. string stack = 2; // the name of the stack being deployed into. string pwd = 3; // the program's working directory. - string program = 4 [deprecated = true]; // the path to the program to execute. + string program = 4 [deprecated = true]; // the path to the program to execute. Deprecated, use info.entry_point instead. repeated string args = 5; // any arguments to pass to the program. map config = 6; // the configuration variables to apply before running. bool dryRun = 7; // true if we're only doing a dryrun (preview). @@ -150,7 +150,7 @@ message RunResponse { } message InstallDependenciesRequest { - string directory = 1 [deprecated = true]; // the program's working directory. + string directory = 1 [deprecated = true]; // the program's working directory. Deprecated, use info.program_directory instead. bool is_terminal = 2; // if we are running in a terminal and should use ANSI codes ProgramInfo info = 3; // the program info to use to execute the plugin. bool use_language_version_tools = 4; // if we should use language version tools like pyenv or @@ -192,7 +192,7 @@ message RuntimeOptionsResponse { message RunPluginRequest{ string pwd = 1; // the program's working directory. - string program = 2 [deprecated = true]; // the path to the program to execute. + string program = 2 [deprecated = true]; // the path to the program to execute. Deprecated, use info.entry_point instead. repeated string args = 3; // any arguments to pass to the program. repeated string env = 4; // any environment variables to set as part of the program. ProgramInfo info = 5; // the program info to use to execute the plugin. diff --git a/proto/pulumi/provider.proto b/proto/pulumi/provider.proto index 4e70fff7..7fa8b08c 100644 --- a/proto/pulumi/provider.proto +++ b/proto/pulumi/provider.proto @@ -48,7 +48,14 @@ service ResourceProvider { rpc CheckConfig(CheckRequest) returns (CheckResponse) {} // DiffConfig checks the impact a hypothetical change to this provider's configuration will have on the provider. rpc DiffConfig(DiffRequest) returns (DiffResponse) {} + // Configure configures the resource provider with "globals" that control its behavior. + // + // :::{warning} + // ConfigureRequest.args may include secrets. Because ConfigureRequest is sent before + // ConfigureResponse can specify acceptSecrets: false, providers *must* handle secrets from + // ConfigureRequest.args. + // ::: rpc Configure(ConfigureRequest) returns (ConfigureResponse) {} // Invoke dynamically executes a built-in function in the provider. @@ -249,6 +256,9 @@ message CheckRequest { reserved "sequenceNumber"; bytes randomSeed = 5; // a deterministically random hash, primarily intended for global unique naming. + + string name = 6; // the Pulumi name for this resource. + string type = 7; // the Pulumi type for this resource. } message CheckResponse { @@ -271,6 +281,8 @@ message DiffRequest { repeated string ignoreChanges = 5; // a set of property paths that should be treated as unchanged. google.protobuf.Struct old_inputs = 6; // the old input values of the resource to diff. + string name = 7; // the Pulumi name for this resource. + string type = 8; // the Pulumi type for this resource. } message PropertyDiff { @@ -342,6 +354,8 @@ message CreateRequest { google.protobuf.Struct properties = 2; // the provider inputs to set during creation. double timeout = 3; // the create request timeout represented in seconds. bool preview = 4; // true if this is a preview and the provider should not actually create the resource. + string name = 5; // the Pulumi name for this resource. + string type = 6; // the Pulumi type for this resource. } message CreateResponse { @@ -356,6 +370,8 @@ message ReadRequest { string urn = 2; // the Pulumi URN for this resource. google.protobuf.Struct properties = 3; // the current state (sufficiently complete to identify the resource). google.protobuf.Struct inputs = 4; // the current inputs, if any (only populated during refresh). + string name = 5; // the Pulumi name for this resource. + string type = 6; // the Pulumi type for this resource. } message ReadResponse { @@ -378,6 +394,8 @@ message UpdateRequest { repeated string ignoreChanges = 6; // a set of property paths that should be treated as unchanged. bool preview = 7; // true if this is a preview and the provider should not actually create the resource. google.protobuf.Struct old_inputs = 8; // the old input values of the resource to diff. + string name = 9; // the Pulumi name for this resource. + string type = 10; // the Pulumi type for this resource. } message UpdateResponse { @@ -390,6 +408,8 @@ message DeleteRequest { google.protobuf.Struct properties = 3; // the current properties on the resource. double timeout = 4; // the delete request timeout represented in seconds. google.protobuf.Struct old_inputs = 5; // the old input values of the resource to delete. + string name = 6; // the Pulumi name for this resource. + string type = 7; // the Pulumi type for this resource. } message ConstructRequest { diff --git a/proto/pulumi/testing/language.proto b/proto/pulumi/testing/language.proto index aac49e8b..5f837be7 100644 --- a/proto/pulumi/testing/language.proto +++ b/proto/pulumi/testing/language.proto @@ -54,6 +54,11 @@ message PrepareLanguageTestsRequest { string core_sdk_directory = 5; string core_sdk_version = 6; repeated Replacement snapshot_edits = 7; + + // a JSON string that will be inserted into every schema loaded (for both GeneratePackage and GenerateProject) in + // the "Languages[language_plugin_name]" field. This can be used to test language specific options such as + // inputTypes in python. + string language_info = 8; } message PrepareLanguageTestsResponse { diff --git a/sdk/Pulumi/Exceptions/InputPropertiesException.cs b/sdk/Pulumi/Exceptions/InputPropertiesException.cs new file mode 100644 index 00000000..ac6821c6 --- /dev/null +++ b/sdk/Pulumi/Exceptions/InputPropertiesException.cs @@ -0,0 +1,51 @@ +// Copyright 2016-2024, Pulumi Corporation + +using System; +using System.Collections.Generic; +using Grpc.Core; +using Pulumirpc; + +namespace Pulumi +{ + public class PropertyError { + public string PropertyPath { get; set; } + public string Reason { get; set; } + + public PropertyError(string propertyPath, string reason) { + PropertyPath = propertyPath; + Reason = reason; + } + } + + public class InputPropertiesException : RpcException + { + public InputPropertiesException(String message, IList propertyErrors) + : base(new Grpc.Core.Status(StatusCode.InvalidArgument, ""), constructTrailers(message, propertyErrors), message) { + } + + public static Metadata constructTrailers(String message, IList propertyErrors) + { + var errorDetails = new InputPropertiesError(); + foreach (var propertyError in propertyErrors) + { + var error = new InputPropertiesError.Types.PropertyError(); + error.PropertyPath = propertyError.PropertyPath; + error.Reason = propertyError.Reason; + errorDetails.Errors.Add(error); + } + var status = new Google.Rpc.Status { + Code = (int)StatusCode.Unknown, + Message = "Bad request", + Details = { Google.Protobuf.WellKnownTypes.Any.Pack(errorDetails) } + }; + +// throw new RpcException(new Grpc.Core.Status(StatusCode.InvalidArgument, "wtf"), "failing for a reason"); + + // var details = Google.Protobuf.WellKnownTypes.Any.Pack(status); + var metadata = new Metadata(); + metadata.Add("grpc-status-details-bin", Google.Protobuf.MessageExtensions.ToByteArray(status)); + Console.WriteLine("metadata: " + metadata.GetAll("grpc-status-details-bin")); + return metadata; + } + } +} diff --git a/sdk/Pulumi/Pulumi.csproj b/sdk/Pulumi/Pulumi.csproj index 95f14b6b..563fe242 100644 --- a/sdk/Pulumi/Pulumi.csproj +++ b/sdk/Pulumi/Pulumi.csproj @@ -30,10 +30,10 @@ - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -44,10 +44,10 @@ - diff --git a/sdk/Pulumi/Pulumi.xml b/sdk/Pulumi/Pulumi.xml index c12feb30..f6df17e1 100644 --- a/sdk/Pulumi/Pulumi.xml +++ b/sdk/Pulumi/Pulumi.xml @@ -4901,6 +4901,44 @@ Field number for the "stackTrace" field. + + + An error that can be returned from a component provider and includes details of the + error, which can be multiple properties. + + + + Field number for the "errors" field. + + + + The list of invalid input properties. + + + + Container for nested types declared in the InputPropertiesError message type. + + + + A single invalid input property. + + + + Field number for the "property_path" field. + + + + The path to the property that is invalid. + + + + Field number for the "reason" field. + + + + The reason the property is invalid. + + Holder for reflection information generated from pulumi/language.proto @@ -4999,7 +5037,7 @@ - the program's working directory. + the program's working directory. Deprecated, use info.program_directory instead. @@ -5007,7 +5045,7 @@ - the path to the program. + the path to the program. Deprecated, use info.entry_point instead. @@ -5063,7 +5101,7 @@ - the program's working directory. + the program's working directory. Deprecated, use info.program_directory instead. @@ -5071,7 +5109,7 @@ - the path to the program. + the path to the program. Deprecated, use info.entry_point instead. @@ -5124,7 +5162,7 @@ - the path to the program to execute. + the path to the program to execute. Deprecated, use info.entry_point instead. @@ -5251,7 +5289,7 @@ - the program's working directory. + the program's working directory. Deprecated, use info.program_directory instead. @@ -5353,7 +5391,7 @@ - the path to the program to execute. + the path to the program to execute. Deprecated, use info.entry_point instead. @@ -6663,6 +6701,22 @@ a deterministically random hash, primarily intended for global unique naming. + + Field number for the "name" field. + + + + the Pulumi name for this resource. + + + + Field number for the "type" field. + + + + the Pulumi type for this resource. + + Field number for the "inputs" field. @@ -6743,6 +6797,22 @@ the old input values of the resource to diff. + + Field number for the "name" field. + + + + the Pulumi name for this resource. + + + + Field number for the "type" field. + + + + the Pulumi type for this resource. + + Field number for the "kind" field. @@ -6928,6 +6998,22 @@ true if this is a preview and the provider should not actually create the resource. + + Field number for the "name" field. + + + + the Pulumi name for this resource. + + + + Field number for the "type" field. + + + + the Pulumi type for this resource. + + NOTE: The partial-update-error equivalent of this message is `ErrorResourceInitFailed`. @@ -6981,6 +7067,22 @@ the current inputs, if any (only populated during refresh). + + Field number for the "name" field. + + + + the Pulumi name for this resource. + + + + Field number for the "type" field. + + + + the Pulumi type for this resource. + + Field number for the "id" field. @@ -7074,6 +7176,22 @@ the old input values of the resource to diff. + + Field number for the "name" field. + + + + the Pulumi name for this resource. + + + + Field number for the "type" field. + + + + the Pulumi type for this resource. + + Field number for the "properties" field. @@ -7122,6 +7240,22 @@ the old input values of the resource to delete. + + Field number for the "name" field. + + + + the Pulumi name for this resource. + + + + Field number for the "type" field. + + + + the Pulumi type for this resource. + + Field number for the "project" field. @@ -7580,12 +7714,18 @@ The response to send back to the client (wrapped by a task). - - Configure configures the resource provider with "globals" that control its behavior. - - The request received from the client. - The context of the server-side call handler being invoked. - The response to send back to the client (wrapped by a task). + + Configure configures the resource provider with "globals" that control its behavior. + + :::{warning} + ConfigureRequest.args may include secrets. Because ConfigureRequest is sent before + ConfigureResponse can specify acceptSecrets: false, providers *must* handle secrets from + ConfigureRequest.args. + ::: + + The request received from the client. + The context of the server-side call handler being invoked. + The response to send back to the client (wrapped by a task). @@ -7933,40 +8073,64 @@ The call object. - - Configure configures the resource provider with "globals" that control its behavior. - - The request to send to the server. - The initial metadata to send with the call. This parameter is optional. - An optional deadline for the call. The call will be cancelled if deadline is hit. - An optional token for canceling the call. - The response received from the server. + + Configure configures the resource provider with "globals" that control its behavior. + + :::{warning} + ConfigureRequest.args may include secrets. Because ConfigureRequest is sent before + ConfigureResponse can specify acceptSecrets: false, providers *must* handle secrets from + ConfigureRequest.args. + ::: + + The request to send to the server. + The initial metadata to send with the call. This parameter is optional. + An optional deadline for the call. The call will be cancelled if deadline is hit. + An optional token for canceling the call. + The response received from the server. - - Configure configures the resource provider with "globals" that control its behavior. - - The request to send to the server. - The options for the call. - The response received from the server. + + Configure configures the resource provider with "globals" that control its behavior. + + :::{warning} + ConfigureRequest.args may include secrets. Because ConfigureRequest is sent before + ConfigureResponse can specify acceptSecrets: false, providers *must* handle secrets from + ConfigureRequest.args. + ::: + + The request to send to the server. + The options for the call. + The response received from the server. - - Configure configures the resource provider with "globals" that control its behavior. - - The request to send to the server. - The initial metadata to send with the call. This parameter is optional. - An optional deadline for the call. The call will be cancelled if deadline is hit. - An optional token for canceling the call. - The call object. + + Configure configures the resource provider with "globals" that control its behavior. + + :::{warning} + ConfigureRequest.args may include secrets. Because ConfigureRequest is sent before + ConfigureResponse can specify acceptSecrets: false, providers *must* handle secrets from + ConfigureRequest.args. + ::: + + The request to send to the server. + The initial metadata to send with the call. This parameter is optional. + An optional deadline for the call. The call will be cancelled if deadline is hit. + An optional token for canceling the call. + The call object. - - Configure configures the resource provider with "globals" that control its behavior. - - The request to send to the server. - The options for the call. - The call object. + + Configure configures the resource provider with "globals" that control its behavior. + + :::{warning} + ConfigureRequest.args may include secrets. Because ConfigureRequest is sent before + ConfigureResponse can specify acceptSecrets: false, providers *must* handle secrets from + ConfigureRequest.args. + ::: + + The request to send to the server. + The options for the call. + The call object. @@ -9764,6 +9928,16 @@ Field number for the "snapshot_edits" field. + + Field number for the "language_info" field. + + + + a JSON string that will be inserted into every schema loaded (for both GeneratePackage and GenerateProject) in + the "Languages[language_plugin_name]" field. This can be used to test language specific options such as + inputTypes in python. + + Container for nested types declared in the PrepareLanguageTestsRequest message type.