diff --git a/pkg/engine/lifecycletest/pulumi_test.go b/pkg/engine/lifecycletest/pulumi_test.go index 227b599cdde9..a41ed1fbf7b7 100644 --- a/pkg/engine/lifecycletest/pulumi_test.go +++ b/pkg/engine/lifecycletest/pulumi_test.go @@ -1473,6 +1473,9 @@ type Resource struct { dependencies []resource.URN parent resource.URN deleteBeforeReplace bool + + aliasSpecs bool + grpcRequestHeaders map[string]string } func registerResources(t *testing.T, monitor *deploytest.ResourceMonitor, resources []Resource) error { @@ -1484,6 +1487,8 @@ func registerResources(t *testing.T, monitor *deploytest.ResourceMonitor, resour DeleteBeforeReplace: &r.deleteBeforeReplace, AliasURNs: r.aliasURNs, Aliases: r.aliases, + AliasSpecs: r.aliasSpecs, + GrpcRequestHeaders: r.grpcRequestHeaders, }) if err != nil { return err @@ -2002,6 +2007,94 @@ func TestAliases(t *testing.T) { }}, []display.StepOp{deploy.OpSame}, false) } +func TestAliasesNodeJSBackCompat(t *testing.T) { + t.Parallel() + + loaders := []*deploytest.ProviderLoader{ + deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) { + return &deploytest.Provider{}, nil + }), + } + + updateProgramWithResource := createUpdateProgramWithResourceFuncForAliasTests(t, loaders) + + tests := []struct { + name string + aliasSpecs bool + grpcRequestHeaders map[string]string + noParentAlias resource.Alias + }{ + { + name: "Old Node SDK", + grpcRequestHeaders: map[string]string{"pulumi-runtime": "nodejs"}, + // Old Node.js SDKs set Parent to "" rather than setting NoParent to true, + noParentAlias: resource.Alias{Parent: ""}, + }, + { + name: "New Node SDK", + grpcRequestHeaders: map[string]string{"pulumi-runtime": "nodejs"}, + // Indicate we're sending alias specs correctly. + aliasSpecs: true, + // Properly set NoParent to true. + noParentAlias: resource.Alias{NoParent: true}, + }, + { + name: "Unknown SDK", + // Properly set NoParent to true. + noParentAlias: resource.Alias{NoParent: true}, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + snap := updateProgramWithResource(nil, []Resource{{ + t: "pkgA:index:t1", + name: "one", + aliasSpecs: tt.aliasSpecs, + grpcRequestHeaders: tt.grpcRequestHeaders, + }, { + t: "pkgA:index:t2", + name: "two", + aliasSpecs: tt.aliasSpecs, + grpcRequestHeaders: tt.grpcRequestHeaders, + }}, []display.StepOp{deploy.OpCreate}, false) + + // Now make "two" a child of "one" ensuring no changes. + snap = updateProgramWithResource(snap, []Resource{{ + t: "pkgA:index:t1", + name: "one", + aliasSpecs: tt.aliasSpecs, + grpcRequestHeaders: tt.grpcRequestHeaders, + }, { + t: "pkgA:index:t2", + parent: "urn:pulumi:test::test::pkgA:index:t1::one", + name: "two", + aliases: []resource.Alias{ + tt.noParentAlias, + }, + aliasSpecs: tt.aliasSpecs, + grpcRequestHeaders: tt.grpcRequestHeaders, + }}, []display.StepOp{deploy.OpSame}, false) + + // Now remove the parent relationship. + _ = updateProgramWithResource(snap, []Resource{{ + t: "pkgA:index:t1", + name: "one", + }, { + t: "pkgA:index:t2", + name: "two", + aliases: []resource.Alias{ + {Parent: "urn:pulumi:test::test::pkgA:index:t1::one"}, + }, + aliasSpecs: tt.aliasSpecs, + grpcRequestHeaders: tt.grpcRequestHeaders, + }}, []display.StepOp{deploy.OpSame}, false) + }) + } +} + func TestAliasURNs(t *testing.T) { t.Parallel() diff --git a/pkg/resource/deploy/deploytest/resourcemonitor.go b/pkg/resource/deploy/deploytest/resourcemonitor.go index 4958266de9b9..7afcba423d5d 100644 --- a/pkg/resource/deploy/deploytest/resourcemonitor.go +++ b/pkg/resource/deploy/deploytest/resourcemonitor.go @@ -27,6 +27,7 @@ import ( pulumirpc "github.com/pulumi/pulumi/sdk/v3/proto/go" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/metadata" ) type ResourceMonitor struct { @@ -108,9 +109,11 @@ type ResourceOptions struct { Remote bool Providers map[string]string AdditionalSecretOutputs []resource.PropertyKey + AliasSpecs bool DisableSecrets bool DisableResourceReferences bool + GrpcRequestHeaders map[string]string } func (rm *ResourceMonitor) RegisterResource(t tokens.Type, name string, custom bool, @@ -228,10 +231,16 @@ func (rm *ResourceMonitor) RegisterResource(t tokens.Type, name string, custom b AdditionalSecretOutputs: additionalSecretOutputs, Aliases: aliasObjects, DeletedWith: string(opts.DeletedWith), + AliasSpecs: opts.AliasSpecs, + } + + ctx := context.Background() + if len(opts.GrpcRequestHeaders) > 0 { + ctx = metadata.NewOutgoingContext(ctx, metadata.New(opts.GrpcRequestHeaders)) } // submit request - resp, err := rm.resmon.RegisterResource(context.Background(), requestInput) + resp, err := rm.resmon.RegisterResource(ctx, requestInput) if err != nil { return "", "", nil, err } diff --git a/pkg/resource/deploy/source_eval.go b/pkg/resource/deploy/source_eval.go index d933f39fd98d..37c73fea68cd 100644 --- a/pkg/resource/deploy/source_eval.go +++ b/pkg/resource/deploy/source_eval.go @@ -30,6 +30,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" "github.com/pulumi/pulumi/pkg/v3/resource/deploy/providers" interceptors "github.com/pulumi/pulumi/pkg/v3/util/rpcdebug" @@ -1006,6 +1007,45 @@ func inheritFromParent(child resource.Goal, parent resource.Goal) *resource.Goal return &goal } +// requestFromNodeJS returns true if the request is coming from a Node.js language runtime +// or SDK. This is determined by checking if the request has a "pulumi-runtime" metadata +// header with a value of "nodejs". If no "pulumi-runtime" header is present, then it +// checks if the request has a "user-agent" metadata header that has a value that starts +// with "grpc-node-js/". +func requestFromNodeJS(ctx context.Context) bool { + if md, hasMetadata := metadata.FromIncomingContext(ctx); hasMetadata { + // Check for the "pulumi-runtime" header first. + // We'll always respect this header value when present. + if runtime, ok := md["pulumi-runtime"]; ok { + return len(runtime) == 1 && runtime[0] == "nodejs" + } + // Otherwise, check the "user-agent" header. + if ua, ok := md["user-agent"]; ok { + return len(ua) == 1 && strings.HasPrefix(ua[0], "grpc-node-js/") + } + } + return false +} + +// transformAliasForNodeJSCompat transforms the alias from the legacy Node.js values to properly specified values. +func transformAliasForNodeJSCompat(alias resource.Alias) resource.Alias { + contract.Assertf(alias.URN == "", "alias.URN must be empty") + // The original implementation in the Node.js SDK did not specify aliases correctly: + // + // - It did not set NoParent when it should have, but instead set Parent to empty. + // - It set NoParent to true and left Parent empty when both the alias and resource had no Parent specified. + // + // To maintain compatibility with such versions of the Node.js SDK, we transform these incorrectly + // specified aliases into properly specified ones that work with this implementation of the engine: + // + // - { Parent: "", NoParent: false } -> { Parent: "", NoParent: true } + // - { Parent: "", NoParent: true } -> { Parent: "", NoParent: false } + if alias.Parent == "" { + alias.NoParent = !alias.NoParent + } + return alias +} + // RegisterResource is invoked by a language process when a new resource has been allocated. func (rm *resmon) RegisterResource(ctx context.Context, req *pulumirpc.RegisterResourceRequest, @@ -1088,6 +1128,13 @@ func (rm *resmon) RegisterResource(ctx context.Context, aliases = append(aliases, resource.Alias{URN: resource.URN(aliasURN)}) } + // We assume aliases are properly specified. However, if a request hasn't explicitly + // indicated that it is using properly specified aliases and the request is coming + // from Node.js, transform the aliases from the incorrect Node.js values to properly + // specified values, to maintain backward compatibility for users of older Node.js + // SDKs that aren't sending properly specified aliases. + transformAliases := !req.GetAliasSpecs() && requestFromNodeJS(ctx) + for _, aliasObject := range req.GetAliases() { aliasSpec := aliasObject.GetSpec() var alias resource.Alias @@ -1100,6 +1147,9 @@ func (rm *resmon) RegisterResource(ctx context.Context, Parent: resource.URN(aliasSpec.GetParentUrn()), NoParent: aliasSpec.GetNoParent(), } + if transformAliases { + alias = transformAliasForNodeJSCompat(alias) + } } else { alias = resource.Alias{ URN: resource.URN(aliasObject.GetUrn()), diff --git a/pkg/resource/deploy/source_eval_test.go b/pkg/resource/deploy/source_eval_test.go index e73fcb442bac..15193378435b 100644 --- a/pkg/resource/deploy/source_eval_test.go +++ b/pkg/resource/deploy/source_eval_test.go @@ -25,6 +25,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "google.golang.org/grpc/metadata" "github.com/pulumi/pulumi/pkg/v3/resource/deploy/deploytest" "github.com/pulumi/pulumi/pkg/v3/resource/deploy/providers" @@ -1164,3 +1165,122 @@ func TestResourceInheritsOptionsFromParent(t *testing.T) { }) } } + +func TestRequestFromNodeJS(t *testing.T) { + t.Parallel() + + ctx := context.Background() + newContext := func(md map[string]string) context.Context { + return metadata.NewIncomingContext(ctx, metadata.New(md)) + } + + tests := []struct { + name string + ctx context.Context + expected bool + }{ + { + name: "no metadata", + ctx: ctx, + expected: false, + }, + { + name: "empty metadata", + ctx: newContext(map[string]string{}), + expected: false, + }, + { + name: "user-agent foo/1.0", + ctx: newContext(map[string]string{"user-agent": "foo/1.0"}), + expected: false, + }, + { + name: "user-agent grpc-node-js/1.8.15", + ctx: newContext(map[string]string{"user-agent": "grpc-node-js/1.8.15"}), + expected: true, + }, + { + name: "pulumi-runtime foo", + ctx: newContext(map[string]string{"pulumi-runtime": "foo"}), + expected: false, + }, + { + name: "pulumi-runtime nodejs", + ctx: newContext(map[string]string{"pulumi-runtime": "nodejs"}), + expected: true, + }, + { + // Always respect the value of pulumi-runtime, regardless of the user-agent. + name: "user-agent grpc-go/1.54.0, pulumi-runtime nodejs", + ctx: newContext(map[string]string{ + "user-agent": "grpc-go/1.54.0", + "pulumi-runtime": "nodejs", + }), + expected: true, + }, + { + name: "user-agent grpc-node-js/1.8.15, pulumi-runtime python", + ctx: newContext(map[string]string{ + "user-agent": "grpc-node-js/1.8.15", + "pulumi-runtime": "python", + }), + expected: false, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + actual := requestFromNodeJS(tt.ctx) + assert.Equal(t, tt.expected, actual) + }) + } +} + +func TestTransformAliasForNodeJSCompat(t *testing.T) { + t.Parallel() + tests := []struct { + name string + input resource.Alias + expected resource.Alias + }{ + { + name: `{Parent: "", NoParent: true} (transformed)`, + input: resource.Alias{Parent: "", NoParent: true}, + expected: resource.Alias{Parent: "", NoParent: false}, + }, + { + name: `{Parent: "", NoParent: false} (transformed)`, + input: resource.Alias{Parent: "", NoParent: false}, + expected: resource.Alias{Parent: "", NoParent: true}, + }, + { + name: `{Parent: "", NoParent: false, Name: "name"} (transformed)`, + input: resource.Alias{Parent: "", NoParent: false, Name: "name"}, + expected: resource.Alias{Parent: "", NoParent: true, Name: "name"}, + }, + { + name: `{Parent: "", NoParent: true, Name: "name"} (transformed)`, + input: resource.Alias{Parent: "", NoParent: true, Name: "name"}, + expected: resource.Alias{Parent: "", NoParent: false, Name: "name"}, + }, + { + name: `{Parent: "foo", NoParent: false} (no transform)`, + input: resource.Alias{Parent: "foo", NoParent: false}, + expected: resource.Alias{Parent: "foo", NoParent: false}, + }, + { + name: `{Parent: "foo", NoParent: false, Name: "name"} (no transform)`, + input: resource.Alias{Parent: "foo", NoParent: false, Name: "name"}, + expected: resource.Alias{Parent: "foo", NoParent: false, Name: "name"}, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + actual := transformAliasForNodeJSCompat(tt.input) + assert.Equal(t, tt.expected, actual) + }) + } +} diff --git a/proto/pulumi/resource.proto b/proto/pulumi/resource.proto index 17b9a17d2ab4..51479e6cdc7e 100644 --- a/proto/pulumi/resource.proto +++ b/proto/pulumi/resource.proto @@ -118,6 +118,15 @@ message RegisterResourceRequest { bool retainOnDelete = 25; // if true the engine will not call the resource providers delete method for this resource. repeated Alias aliases = 26; // a list of additional aliases that should be considered the same. string deletedWith = 27; // if set the engine will not call the resource providers delete method for this resource when specified resource is deleted. + + // Indicates that alias specs are specified correctly according to the spec. + // Older versions of the Node.js SDK did not send alias specs correctly. + // If this is not set to true and the engine detects the request is from the + // Node.js runtime, the engine will transform incorrect alias specs into + // correct ones. + // Other SDKs that are correctly specifying alias specs could set this to + // true, but it's not necessary. + bool aliasSpecs = 28; } // RegisterResourceResponse is returned by the engine after a resource has finished being initialized. It includes the diff --git a/sdk/nodejs/cmd/pulumi-language-nodejs/proxy.go b/sdk/nodejs/cmd/pulumi-language-nodejs/proxy.go index ffd313d47fb7..80d9afe72bd9 100644 --- a/sdk/nodejs/cmd/pulumi-language-nodejs/proxy.go +++ b/sdk/nodejs/cmd/pulumi-language-nodejs/proxy.go @@ -23,6 +23,7 @@ import ( "google.golang.org/grpc/encoding" "google.golang.org/grpc/encoding/proto" + "google.golang.org/grpc/metadata" "github.com/pulumi/pulumi/sdk/v3/go/common/util/logging" pulumirpc "github.com/pulumi/pulumi/sdk/v3/proto/go" @@ -231,6 +232,7 @@ func (p *monitorProxy) ReadResource( func (p *monitorProxy) RegisterResource( ctx context.Context, req *pulumirpc.RegisterResourceRequest, ) (*pulumirpc.RegisterResourceResponse, error) { + ctx = metadata.AppendToOutgoingContext(ctx, "pulumi-runtime", "nodejs") return p.target.RegisterResource(ctx, req) } diff --git a/sdk/nodejs/proto/resource_pb.js b/sdk/nodejs/proto/resource_pb.js index e4b7e962f53c..e6f663e62279 100644 --- a/sdk/nodejs/proto/resource_pb.js +++ b/sdk/nodejs/proto/resource_pb.js @@ -1298,7 +1298,8 @@ proto.pulumirpc.RegisterResourceRequest.toObject = function(includeInstance, msg retainondelete: jspb.Message.getBooleanFieldWithDefault(msg, 25, false), aliasesList: jspb.Message.toObjectList(msg.getAliasesList(), pulumi_alias_pb.Alias.toObject, includeInstance), - deletedwith: jspb.Message.getFieldWithDefault(msg, 27, "") + deletedwith: jspb.Message.getFieldWithDefault(msg, 27, ""), + aliasspecs: jspb.Message.getBooleanFieldWithDefault(msg, 28, false) }; if (includeInstance) { @@ -1450,6 +1451,10 @@ proto.pulumirpc.RegisterResourceRequest.deserializeBinaryFromReader = function(m var value = /** @type {string} */ (reader.readString()); msg.setDeletedwith(value); break; + case 28: + var value = /** @type {boolean} */ (reader.readBool()); + msg.setAliasspecs(value); + break; default: reader.skipField(); break; @@ -1665,6 +1670,13 @@ proto.pulumirpc.RegisterResourceRequest.serializeBinaryToWriter = function(messa f ); } + f = message.getAliasspecs(); + if (f) { + writer.writeBool( + 28, + f + ); + } }; @@ -2661,6 +2673,24 @@ proto.pulumirpc.RegisterResourceRequest.prototype.setDeletedwith = function(valu }; +/** + * optional bool aliasSpecs = 28; + * @return {boolean} + */ +proto.pulumirpc.RegisterResourceRequest.prototype.getAliasspecs = function() { + return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 28, false)); +}; + + +/** + * @param {boolean} value + * @return {!proto.pulumirpc.RegisterResourceRequest} returns this + */ +proto.pulumirpc.RegisterResourceRequest.prototype.setAliasspecs = function(value) { + return jspb.Message.setProto3BooleanField(this, 28, value); +}; + + /** * List of repeated fields within this message type. diff --git a/sdk/nodejs/runtime/resource.ts b/sdk/nodejs/runtime/resource.ts index f48c4ad847d5..0eab1c994791 100644 --- a/sdk/nodejs/runtime/resource.ts +++ b/sdk/nodejs/runtime/resource.ts @@ -433,6 +433,7 @@ export function registerResource( req.setPlugindownloadurl(opts.pluginDownloadURL || ""); req.setRetainondelete(opts.retainOnDelete || false); req.setDeletedwith(resop.deletedWithURN || ""); + req.setAliasspecs(true); if (resop.deletedWithURN && !(await monitorSupportsDeletedWith())) { throw new Error( diff --git a/sdk/proto/go/resource.pb.go b/sdk/proto/go/resource.pb.go index 9538526f55a7..9e58a512b89c 100644 --- a/sdk/proto/go/resource.pb.go +++ b/sdk/proto/go/resource.pb.go @@ -357,6 +357,7 @@ type RegisterResourceRequest struct { RetainOnDelete bool `protobuf:"varint,25,opt,name=retainOnDelete,proto3" json:"retainOnDelete,omitempty"` // if true the engine will not call the resource providers delete method for this resource. Aliases []*Alias `protobuf:"bytes,26,rep,name=aliases,proto3" json:"aliases,omitempty"` // a list of additional aliases that should be considered the same. DeletedWith string `protobuf:"bytes,27,opt,name=deletedWith,proto3" json:"deletedWith,omitempty"` // if set the engine will not call the resource providers delete method for this resource when specified resource is deleted. + AliasSpecs bool `protobuf:"varint,28,opt,name=aliasSpecs,proto3" json:"aliasSpecs,omitempty"` // if set, it indicates that any specified aliases are specified correctly according to the spec. } func (x *RegisterResourceRequest) Reset() { @@ -580,6 +581,13 @@ func (x *RegisterResourceRequest) GetDeletedWith() string { return "" } +func (x *RegisterResourceRequest) GetAliasSpecs() bool { + if x != nil { + return x.AliasSpecs + } + return false +} + // RegisterResourceResponse is returned by the engine after a resource has finished being initialized. It includes the // auto-assigned URN, the provider-assigned ID, and any other properties initialized by the engine. type RegisterResourceResponse struct { @@ -1024,7 +1032,7 @@ var file_pulumi_resource_proto_rawDesc = []byte{ 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, - 0x65, 0x73, 0x22, 0xf5, 0x0b, 0x0a, 0x17, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, + 0x65, 0x73, 0x22, 0x95, 0x0c, 0x0a, 0x17, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, @@ -1099,7 +1107,9 @@ var file_pulumi_resource_proto_rawDesc = []byte{ 0x70, 0x63, 0x2e, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x07, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x57, 0x69, 0x74, 0x68, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x57, - 0x69, 0x74, 0x68, 0x1a, 0x2a, 0x0a, 0x14, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x44, + 0x69, 0x74, 0x68, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x53, 0x70, 0x65, 0x63, + 0x73, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x53, 0x70, + 0x65, 0x63, 0x73, 0x1a, 0x2a, 0x0a, 0x14, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x72, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x75, 0x72, 0x6e, 0x73, 0x1a, 0x58, 0x0a, 0x0e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, diff --git a/sdk/python/lib/pulumi/runtime/proto/resource_pb2.py b/sdk/python/lib/pulumi/runtime/proto/resource_pb2.py index 5d58a4f9202f..7ddb77025a9c 100644 --- a/sdk/python/lib/pulumi/runtime/proto/resource_pb2.py +++ b/sdk/python/lib/pulumi/runtime/proto/resource_pb2.py @@ -17,7 +17,7 @@ from . import alias_pb2 as pulumi_dot_alias__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x15pulumi/resource.proto\x12\tpulumirpc\x1a\x1bgoogle/protobuf/empty.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a\x15pulumi/provider.proto\x1a\x12pulumi/alias.proto\"$\n\x16SupportsFeatureRequest\x12\n\n\x02id\x18\x01 \x01(\t\"-\n\x17SupportsFeatureResponse\x12\x12\n\nhasSupport\x18\x01 \x01(\x08\"\xae\x02\n\x13ReadResourceRequest\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04type\x18\x02 \x01(\t\x12\x0c\n\x04name\x18\x03 \x01(\t\x12\x0e\n\x06parent\x18\x04 \x01(\t\x12+\n\nproperties\x18\x05 \x01(\x0b\x32\x17.google.protobuf.Struct\x12\x14\n\x0c\x64\x65pendencies\x18\x06 \x03(\t\x12\x10\n\x08provider\x18\x07 \x01(\t\x12\x0f\n\x07version\x18\x08 \x01(\t\x12\x15\n\racceptSecrets\x18\t \x01(\x08\x12\x1f\n\x17\x61\x64\x64itionalSecretOutputs\x18\n \x03(\t\x12\x17\n\x0f\x61\x63\x63\x65ptResources\x18\x0c \x01(\x08\x12\x19\n\x11pluginDownloadURL\x18\r \x01(\tJ\x04\x08\x0b\x10\x0cR\x07\x61liases\"P\n\x14ReadResourceResponse\x12\x0b\n\x03urn\x18\x01 \x01(\t\x12+\n\nproperties\x18\x02 \x01(\x0b\x32\x17.google.protobuf.Struct\"\xc7\x08\n\x17RegisterResourceRequest\x12\x0c\n\x04type\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0e\n\x06parent\x18\x03 \x01(\t\x12\x0e\n\x06\x63ustom\x18\x04 \x01(\x08\x12\'\n\x06object\x18\x05 \x01(\x0b\x32\x17.google.protobuf.Struct\x12\x0f\n\x07protect\x18\x06 \x01(\x08\x12\x14\n\x0c\x64\x65pendencies\x18\x07 \x03(\t\x12\x10\n\x08provider\x18\x08 \x01(\t\x12Z\n\x14propertyDependencies\x18\t \x03(\x0b\x32<.pulumirpc.RegisterResourceRequest.PropertyDependenciesEntry\x12\x1b\n\x13\x64\x65leteBeforeReplace\x18\n \x01(\x08\x12\x0f\n\x07version\x18\x0b \x01(\t\x12\x15\n\rignoreChanges\x18\x0c \x03(\t\x12\x15\n\racceptSecrets\x18\r \x01(\x08\x12\x1f\n\x17\x61\x64\x64itionalSecretOutputs\x18\x0e \x03(\t\x12\x11\n\taliasURNs\x18\x0f \x03(\t\x12\x10\n\x08importId\x18\x10 \x01(\t\x12I\n\x0e\x63ustomTimeouts\x18\x11 \x01(\x0b\x32\x31.pulumirpc.RegisterResourceRequest.CustomTimeouts\x12\"\n\x1a\x64\x65leteBeforeReplaceDefined\x18\x12 \x01(\x08\x12\x1d\n\x15supportsPartialValues\x18\x13 \x01(\x08\x12\x0e\n\x06remote\x18\x14 \x01(\x08\x12\x17\n\x0f\x61\x63\x63\x65ptResources\x18\x15 \x01(\x08\x12\x44\n\tproviders\x18\x16 \x03(\x0b\x32\x31.pulumirpc.RegisterResourceRequest.ProvidersEntry\x12\x18\n\x10replaceOnChanges\x18\x17 \x03(\t\x12\x19\n\x11pluginDownloadURL\x18\x18 \x01(\t\x12\x16\n\x0eretainOnDelete\x18\x19 \x01(\x08\x12!\n\x07\x61liases\x18\x1a \x03(\x0b\x32\x10.pulumirpc.Alias\x12\x13\n\x0b\x64\x65letedWith\x18\x1b \x01(\t\x1a$\n\x14PropertyDependencies\x12\x0c\n\x04urns\x18\x01 \x03(\t\x1a@\n\x0e\x43ustomTimeouts\x12\x0e\n\x06\x63reate\x18\x01 \x01(\t\x12\x0e\n\x06update\x18\x02 \x01(\t\x12\x0e\n\x06\x64\x65lete\x18\x03 \x01(\t\x1at\n\x19PropertyDependenciesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x46\n\x05value\x18\x02 \x01(\x0b\x32\x37.pulumirpc.RegisterResourceRequest.PropertyDependencies:\x02\x38\x01\x1a\x30\n\x0eProvidersEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xf7\x02\n\x18RegisterResourceResponse\x12\x0b\n\x03urn\x18\x01 \x01(\t\x12\n\n\x02id\x18\x02 \x01(\t\x12\'\n\x06object\x18\x03 \x01(\x0b\x32\x17.google.protobuf.Struct\x12\x0e\n\x06stable\x18\x04 \x01(\x08\x12\x0f\n\x07stables\x18\x05 \x03(\t\x12[\n\x14propertyDependencies\x18\x06 \x03(\x0b\x32=.pulumirpc.RegisterResourceResponse.PropertyDependenciesEntry\x1a$\n\x14PropertyDependencies\x12\x0c\n\x04urns\x18\x01 \x03(\t\x1au\n\x19PropertyDependenciesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12G\n\x05value\x18\x02 \x01(\x0b\x32\x38.pulumirpc.RegisterResourceResponse.PropertyDependencies:\x02\x38\x01\"W\n\x1eRegisterResourceOutputsRequest\x12\x0b\n\x03urn\x18\x01 \x01(\t\x12(\n\x07outputs\x18\x02 \x01(\x0b\x32\x17.google.protobuf.Struct\"\xa2\x01\n\x15ResourceInvokeRequest\x12\x0b\n\x03tok\x18\x01 \x01(\t\x12%\n\x04\x61rgs\x18\x02 \x01(\x0b\x32\x17.google.protobuf.Struct\x12\x10\n\x08provider\x18\x03 \x01(\t\x12\x0f\n\x07version\x18\x04 \x01(\t\x12\x17\n\x0f\x61\x63\x63\x65ptResources\x18\x05 \x01(\x08\x12\x19\n\x11pluginDownloadURL\x18\x06 \x01(\t2\xd4\x04\n\x0fResourceMonitor\x12Z\n\x0fSupportsFeature\x12!.pulumirpc.SupportsFeatureRequest\x1a\".pulumirpc.SupportsFeatureResponse\"\x00\x12G\n\x06Invoke\x12 .pulumirpc.ResourceInvokeRequest\x1a\x19.pulumirpc.InvokeResponse\"\x00\x12O\n\x0cStreamInvoke\x12 .pulumirpc.ResourceInvokeRequest\x1a\x19.pulumirpc.InvokeResponse\"\x00\x30\x01\x12\x39\n\x04\x43\x61ll\x12\x16.pulumirpc.CallRequest\x1a\x17.pulumirpc.CallResponse\"\x00\x12Q\n\x0cReadResource\x12\x1e.pulumirpc.ReadResourceRequest\x1a\x1f.pulumirpc.ReadResourceResponse\"\x00\x12]\n\x10RegisterResource\x12\".pulumirpc.RegisterResourceRequest\x1a#.pulumirpc.RegisterResourceResponse\"\x00\x12^\n\x17RegisterResourceOutputs\x12).pulumirpc.RegisterResourceOutputsRequest\x1a\x16.google.protobuf.Empty\"\x00\x42\x34Z2github.com/pulumi/pulumi/sdk/v3/proto/go;pulumirpcb\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x15pulumi/resource.proto\x12\tpulumirpc\x1a\x1bgoogle/protobuf/empty.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a\x15pulumi/provider.proto\x1a\x12pulumi/alias.proto\"$\n\x16SupportsFeatureRequest\x12\n\n\x02id\x18\x01 \x01(\t\"-\n\x17SupportsFeatureResponse\x12\x12\n\nhasSupport\x18\x01 \x01(\x08\"\xae\x02\n\x13ReadResourceRequest\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04type\x18\x02 \x01(\t\x12\x0c\n\x04name\x18\x03 \x01(\t\x12\x0e\n\x06parent\x18\x04 \x01(\t\x12+\n\nproperties\x18\x05 \x01(\x0b\x32\x17.google.protobuf.Struct\x12\x14\n\x0c\x64\x65pendencies\x18\x06 \x03(\t\x12\x10\n\x08provider\x18\x07 \x01(\t\x12\x0f\n\x07version\x18\x08 \x01(\t\x12\x15\n\racceptSecrets\x18\t \x01(\x08\x12\x1f\n\x17\x61\x64\x64itionalSecretOutputs\x18\n \x03(\t\x12\x17\n\x0f\x61\x63\x63\x65ptResources\x18\x0c \x01(\x08\x12\x19\n\x11pluginDownloadURL\x18\r \x01(\tJ\x04\x08\x0b\x10\x0cR\x07\x61liases\"P\n\x14ReadResourceResponse\x12\x0b\n\x03urn\x18\x01 \x01(\t\x12+\n\nproperties\x18\x02 \x01(\x0b\x32\x17.google.protobuf.Struct\"\xdb\x08\n\x17RegisterResourceRequest\x12\x0c\n\x04type\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0e\n\x06parent\x18\x03 \x01(\t\x12\x0e\n\x06\x63ustom\x18\x04 \x01(\x08\x12\'\n\x06object\x18\x05 \x01(\x0b\x32\x17.google.protobuf.Struct\x12\x0f\n\x07protect\x18\x06 \x01(\x08\x12\x14\n\x0c\x64\x65pendencies\x18\x07 \x03(\t\x12\x10\n\x08provider\x18\x08 \x01(\t\x12Z\n\x14propertyDependencies\x18\t \x03(\x0b\x32<.pulumirpc.RegisterResourceRequest.PropertyDependenciesEntry\x12\x1b\n\x13\x64\x65leteBeforeReplace\x18\n \x01(\x08\x12\x0f\n\x07version\x18\x0b \x01(\t\x12\x15\n\rignoreChanges\x18\x0c \x03(\t\x12\x15\n\racceptSecrets\x18\r \x01(\x08\x12\x1f\n\x17\x61\x64\x64itionalSecretOutputs\x18\x0e \x03(\t\x12\x11\n\taliasURNs\x18\x0f \x03(\t\x12\x10\n\x08importId\x18\x10 \x01(\t\x12I\n\x0e\x63ustomTimeouts\x18\x11 \x01(\x0b\x32\x31.pulumirpc.RegisterResourceRequest.CustomTimeouts\x12\"\n\x1a\x64\x65leteBeforeReplaceDefined\x18\x12 \x01(\x08\x12\x1d\n\x15supportsPartialValues\x18\x13 \x01(\x08\x12\x0e\n\x06remote\x18\x14 \x01(\x08\x12\x17\n\x0f\x61\x63\x63\x65ptResources\x18\x15 \x01(\x08\x12\x44\n\tproviders\x18\x16 \x03(\x0b\x32\x31.pulumirpc.RegisterResourceRequest.ProvidersEntry\x12\x18\n\x10replaceOnChanges\x18\x17 \x03(\t\x12\x19\n\x11pluginDownloadURL\x18\x18 \x01(\t\x12\x16\n\x0eretainOnDelete\x18\x19 \x01(\x08\x12!\n\x07\x61liases\x18\x1a \x03(\x0b\x32\x10.pulumirpc.Alias\x12\x13\n\x0b\x64\x65letedWith\x18\x1b \x01(\t\x12\x12\n\naliasSpecs\x18\x1c \x01(\x08\x1a$\n\x14PropertyDependencies\x12\x0c\n\x04urns\x18\x01 \x03(\t\x1a@\n\x0e\x43ustomTimeouts\x12\x0e\n\x06\x63reate\x18\x01 \x01(\t\x12\x0e\n\x06update\x18\x02 \x01(\t\x12\x0e\n\x06\x64\x65lete\x18\x03 \x01(\t\x1at\n\x19PropertyDependenciesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x46\n\x05value\x18\x02 \x01(\x0b\x32\x37.pulumirpc.RegisterResourceRequest.PropertyDependencies:\x02\x38\x01\x1a\x30\n\x0eProvidersEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xf7\x02\n\x18RegisterResourceResponse\x12\x0b\n\x03urn\x18\x01 \x01(\t\x12\n\n\x02id\x18\x02 \x01(\t\x12\'\n\x06object\x18\x03 \x01(\x0b\x32\x17.google.protobuf.Struct\x12\x0e\n\x06stable\x18\x04 \x01(\x08\x12\x0f\n\x07stables\x18\x05 \x03(\t\x12[\n\x14propertyDependencies\x18\x06 \x03(\x0b\x32=.pulumirpc.RegisterResourceResponse.PropertyDependenciesEntry\x1a$\n\x14PropertyDependencies\x12\x0c\n\x04urns\x18\x01 \x03(\t\x1au\n\x19PropertyDependenciesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12G\n\x05value\x18\x02 \x01(\x0b\x32\x38.pulumirpc.RegisterResourceResponse.PropertyDependencies:\x02\x38\x01\"W\n\x1eRegisterResourceOutputsRequest\x12\x0b\n\x03urn\x18\x01 \x01(\t\x12(\n\x07outputs\x18\x02 \x01(\x0b\x32\x17.google.protobuf.Struct\"\xa2\x01\n\x15ResourceInvokeRequest\x12\x0b\n\x03tok\x18\x01 \x01(\t\x12%\n\x04\x61rgs\x18\x02 \x01(\x0b\x32\x17.google.protobuf.Struct\x12\x10\n\x08provider\x18\x03 \x01(\t\x12\x0f\n\x07version\x18\x04 \x01(\t\x12\x17\n\x0f\x61\x63\x63\x65ptResources\x18\x05 \x01(\x08\x12\x19\n\x11pluginDownloadURL\x18\x06 \x01(\t2\xd4\x04\n\x0fResourceMonitor\x12Z\n\x0fSupportsFeature\x12!.pulumirpc.SupportsFeatureRequest\x1a\".pulumirpc.SupportsFeatureResponse\"\x00\x12G\n\x06Invoke\x12 .pulumirpc.ResourceInvokeRequest\x1a\x19.pulumirpc.InvokeResponse\"\x00\x12O\n\x0cStreamInvoke\x12 .pulumirpc.ResourceInvokeRequest\x1a\x19.pulumirpc.InvokeResponse\"\x00\x30\x01\x12\x39\n\x04\x43\x61ll\x12\x16.pulumirpc.CallRequest\x1a\x17.pulumirpc.CallResponse\"\x00\x12Q\n\x0cReadResource\x12\x1e.pulumirpc.ReadResourceRequest\x1a\x1f.pulumirpc.ReadResourceResponse\"\x00\x12]\n\x10RegisterResource\x12\".pulumirpc.RegisterResourceRequest\x1a#.pulumirpc.RegisterResourceResponse\"\x00\x12^\n\x17RegisterResourceOutputs\x12).pulumirpc.RegisterResourceOutputsRequest\x1a\x16.google.protobuf.Empty\"\x00\x42\x34Z2github.com/pulumi/pulumi/sdk/v3/proto/go;pulumirpcb\x06proto3') _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'pulumi.resource_pb2', globals()) @@ -40,25 +40,25 @@ _READRESOURCERESPONSE._serialized_start=528 _READRESOURCERESPONSE._serialized_end=608 _REGISTERRESOURCEREQUEST._serialized_start=611 - _REGISTERRESOURCEREQUEST._serialized_end=1706 - _REGISTERRESOURCEREQUEST_PROPERTYDEPENDENCIES._serialized_start=1436 - _REGISTERRESOURCEREQUEST_PROPERTYDEPENDENCIES._serialized_end=1472 - _REGISTERRESOURCEREQUEST_CUSTOMTIMEOUTS._serialized_start=1474 - _REGISTERRESOURCEREQUEST_CUSTOMTIMEOUTS._serialized_end=1538 - _REGISTERRESOURCEREQUEST_PROPERTYDEPENDENCIESENTRY._serialized_start=1540 - _REGISTERRESOURCEREQUEST_PROPERTYDEPENDENCIESENTRY._serialized_end=1656 - _REGISTERRESOURCEREQUEST_PROVIDERSENTRY._serialized_start=1658 - _REGISTERRESOURCEREQUEST_PROVIDERSENTRY._serialized_end=1706 - _REGISTERRESOURCERESPONSE._serialized_start=1709 - _REGISTERRESOURCERESPONSE._serialized_end=2084 - _REGISTERRESOURCERESPONSE_PROPERTYDEPENDENCIES._serialized_start=1436 - _REGISTERRESOURCERESPONSE_PROPERTYDEPENDENCIES._serialized_end=1472 - _REGISTERRESOURCERESPONSE_PROPERTYDEPENDENCIESENTRY._serialized_start=1967 - _REGISTERRESOURCERESPONSE_PROPERTYDEPENDENCIESENTRY._serialized_end=2084 - _REGISTERRESOURCEOUTPUTSREQUEST._serialized_start=2086 - _REGISTERRESOURCEOUTPUTSREQUEST._serialized_end=2173 - _RESOURCEINVOKEREQUEST._serialized_start=2176 - _RESOURCEINVOKEREQUEST._serialized_end=2338 - _RESOURCEMONITOR._serialized_start=2341 - _RESOURCEMONITOR._serialized_end=2937 + _REGISTERRESOURCEREQUEST._serialized_end=1726 + _REGISTERRESOURCEREQUEST_PROPERTYDEPENDENCIES._serialized_start=1456 + _REGISTERRESOURCEREQUEST_PROPERTYDEPENDENCIES._serialized_end=1492 + _REGISTERRESOURCEREQUEST_CUSTOMTIMEOUTS._serialized_start=1494 + _REGISTERRESOURCEREQUEST_CUSTOMTIMEOUTS._serialized_end=1558 + _REGISTERRESOURCEREQUEST_PROPERTYDEPENDENCIESENTRY._serialized_start=1560 + _REGISTERRESOURCEREQUEST_PROPERTYDEPENDENCIESENTRY._serialized_end=1676 + _REGISTERRESOURCEREQUEST_PROVIDERSENTRY._serialized_start=1678 + _REGISTERRESOURCEREQUEST_PROVIDERSENTRY._serialized_end=1726 + _REGISTERRESOURCERESPONSE._serialized_start=1729 + _REGISTERRESOURCERESPONSE._serialized_end=2104 + _REGISTERRESOURCERESPONSE_PROPERTYDEPENDENCIES._serialized_start=1456 + _REGISTERRESOURCERESPONSE_PROPERTYDEPENDENCIES._serialized_end=1492 + _REGISTERRESOURCERESPONSE_PROPERTYDEPENDENCIESENTRY._serialized_start=1987 + _REGISTERRESOURCERESPONSE_PROPERTYDEPENDENCIESENTRY._serialized_end=2104 + _REGISTERRESOURCEOUTPUTSREQUEST._serialized_start=2106 + _REGISTERRESOURCEOUTPUTSREQUEST._serialized_end=2193 + _RESOURCEINVOKEREQUEST._serialized_start=2196 + _RESOURCEINVOKEREQUEST._serialized_end=2358 + _RESOURCEMONITOR._serialized_start=2361 + _RESOURCEMONITOR._serialized_end=2957 # @@protoc_insertion_point(module_scope) diff --git a/sdk/python/lib/pulumi/runtime/proto/resource_pb2.pyi b/sdk/python/lib/pulumi/runtime/proto/resource_pb2.pyi index a2636e2f41a2..5a2e9d9c36b2 100644 --- a/sdk/python/lib/pulumi/runtime/proto/resource_pb2.pyi +++ b/sdk/python/lib/pulumi/runtime/proto/resource_pb2.pyi @@ -272,6 +272,7 @@ class RegisterResourceRequest(google.protobuf.message.Message): RETAINONDELETE_FIELD_NUMBER: builtins.int ALIASES_FIELD_NUMBER: builtins.int DELETEDWITH_FIELD_NUMBER: builtins.int + ALIASSPECS_FIELD_NUMBER: builtins.int type: builtins.str """the type of the object allocated.""" name: builtins.str @@ -336,6 +337,8 @@ class RegisterResourceRequest(google.protobuf.message.Message): """a list of additional aliases that should be considered the same.""" deletedWith: builtins.str """if set the engine will not call the resource providers delete method for this resource when specified resource is deleted.""" + aliasSpecs: builtins.bool + """if set, it indicates that any specified aliases are specified correctly according to the spec.""" def __init__( self, *, @@ -366,9 +369,10 @@ class RegisterResourceRequest(google.protobuf.message.Message): retainOnDelete: builtins.bool = ..., aliases: collections.abc.Iterable[pulumi.alias_pb2.Alias] | None = ..., deletedWith: builtins.str = ..., + aliasSpecs: builtins.bool = ..., ) -> None: ... def HasField(self, field_name: typing_extensions.Literal["customTimeouts", b"customTimeouts", "object", b"object"]) -> builtins.bool: ... - def ClearField(self, field_name: typing_extensions.Literal["acceptResources", b"acceptResources", "acceptSecrets", b"acceptSecrets", "additionalSecretOutputs", b"additionalSecretOutputs", "aliasURNs", b"aliasURNs", "aliases", b"aliases", "custom", b"custom", "customTimeouts", b"customTimeouts", "deleteBeforeReplace", b"deleteBeforeReplace", "deleteBeforeReplaceDefined", b"deleteBeforeReplaceDefined", "deletedWith", b"deletedWith", "dependencies", b"dependencies", "ignoreChanges", b"ignoreChanges", "importId", b"importId", "name", b"name", "object", b"object", "parent", b"parent", "pluginDownloadURL", b"pluginDownloadURL", "propertyDependencies", b"propertyDependencies", "protect", b"protect", "provider", b"provider", "providers", b"providers", "remote", b"remote", "replaceOnChanges", b"replaceOnChanges", "retainOnDelete", b"retainOnDelete", "supportsPartialValues", b"supportsPartialValues", "type", b"type", "version", b"version"]) -> None: ... + def ClearField(self, field_name: typing_extensions.Literal["acceptResources", b"acceptResources", "acceptSecrets", b"acceptSecrets", "additionalSecretOutputs", b"additionalSecretOutputs", "aliasSpecs", b"aliasSpecs", "aliasURNs", b"aliasURNs", "aliases", b"aliases", "custom", b"custom", "customTimeouts", b"customTimeouts", "deleteBeforeReplace", b"deleteBeforeReplace", "deleteBeforeReplaceDefined", b"deleteBeforeReplaceDefined", "deletedWith", b"deletedWith", "dependencies", b"dependencies", "ignoreChanges", b"ignoreChanges", "importId", b"importId", "name", b"name", "object", b"object", "parent", b"parent", "pluginDownloadURL", b"pluginDownloadURL", "propertyDependencies", b"propertyDependencies", "protect", b"protect", "provider", b"provider", "providers", b"providers", "remote", b"remote", "replaceOnChanges", b"replaceOnChanges", "retainOnDelete", b"retainOnDelete", "supportsPartialValues", b"supportsPartialValues", "type", b"type", "version", b"version"]) -> None: ... global___RegisterResourceRequest = RegisterResourceRequest