diff --git a/CHANGELOG.md b/CHANGELOG.md index 32c178b93..659d55be6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,8 @@ CHANGELOG ## HEAD (Unreleased) -_(None)_ +- Add internal scaffolding for using cross-language components from Python. + [#5375](https://github.com/pulumi/pulumi/pull/5375) ## 2.11.0 (2020-09-30) @@ -18,7 +19,6 @@ _(None)_ (fixes [#5446](https://github.com/pulumi/pulumi/issues/5446)) [#5465](https://github.com/pulumi/pulumi/pull/5465) - ## 2.10.2 (2020-09-21) - [sdk/go] Add missing Version field to invokeOptions @@ -26,7 +26,7 @@ _(None)_ - Add `pulumi console` command which opens the currently selected stack in the Pulumi console. [#5368](https://github.com/pulumi/pulumi/pull/5368) - + - Python SDK: Cast numbers intended to be integers to `int`. [#5419](https://github.com/pulumi/pulumi/pull/5419) diff --git a/pkg/testing/integration/program.go b/pkg/testing/integration/program.go index d549b77ce..66f049d2b 100644 --- a/pkg/testing/integration/program.go +++ b/pkg/testing/integration/program.go @@ -1570,6 +1570,36 @@ func (pt *ProgramTester) copyTestToTemporaryDirectory() (string, string, error) return "", "", errors.Wrapf(err, "Failed to prepare %v", projdir) } + // TODO[pulumi/pulumi#5455]: Dynamic providers fail to load when used from multi-lang components. + // Until that's been fixed, this environment variable can be set by a test, which results in + // a package.json being emitted in the project directory and `yarn install && yarn link @pulumi/pulumi` + // being run. + // When the underlying issue has been fixed, the use of this environment variable should be removed. + var yarnLinkPulumi bool + for _, env := range pt.opts.Env { + if env == "PULUMI_TEST_YARN_LINK_PULUMI=true" { + yarnLinkPulumi = true + break + } + } + if yarnLinkPulumi { + const packageJSON = `{ + "name": "test", + "peerDependencies": { + "@pulumi/pulumi": "latest" + } + }` + if err := ioutil.WriteFile(filepath.Join(projdir, "package.json"), []byte(packageJSON), 0600); err != nil { + return "", "", err + } + if err = pt.runYarnCommand("yarn-install", []string{"install"}, projdir); err != nil { + return "", "", err + } + if err := pt.runYarnCommand("yarn-link", []string{"link", "@pulumi/pulumi"}, projdir); err != nil { + return "", "", err + } + } + fprintf(stdout, "projdir: %v\n", projdir) return tmpdir, projdir, nil } diff --git a/sdk/nodejs/proto/resource_pb.js b/sdk/nodejs/proto/resource_pb.js index d19e5847f..cdb7ad02d 100644 --- a/sdk/nodejs/proto/resource_pb.js +++ b/sdk/nodejs/proto/resource_pb.js @@ -1252,7 +1252,7 @@ proto.pulumirpc.RegisterResourceRequest.toObject = function(includeInstance, msg customtimeouts: (f = msg.getCustomtimeouts()) && proto.pulumirpc.RegisterResourceRequest.CustomTimeouts.toObject(includeInstance, f), deletebeforereplacedefined: jspb.Message.getBooleanFieldWithDefault(msg, 18, false), supportspartialvalues: jspb.Message.getBooleanFieldWithDefault(msg, 19, false), - remote: jspb.Message.getBooleanFieldWithDefault(msg, 21, false) + remote: jspb.Message.getBooleanFieldWithDefault(msg, 20, false) }; if (includeInstance) { @@ -1369,7 +1369,7 @@ proto.pulumirpc.RegisterResourceRequest.deserializeBinaryFromReader = function(m var value = /** @type {boolean} */ (reader.readBool()); msg.setSupportspartialvalues(value); break; - case 21: + case 20: var value = /** @type {boolean} */ (reader.readBool()); msg.setRemote(value); break; @@ -1537,7 +1537,7 @@ proto.pulumirpc.RegisterResourceRequest.serializeBinaryToWriter = function(messa f = message.getRemote(); if (f) { writer.writeBool( - 21, + 20, f ); } @@ -2351,11 +2351,11 @@ proto.pulumirpc.RegisterResourceRequest.prototype.setSupportspartialvalues = fun /** - * optional bool remote = 21; + * optional bool remote = 20; * @return {boolean} */ proto.pulumirpc.RegisterResourceRequest.prototype.getRemote = function() { - return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 21, false)); + return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 20, false)); }; @@ -2364,7 +2364,7 @@ proto.pulumirpc.RegisterResourceRequest.prototype.getRemote = function() { * @return {!proto.pulumirpc.RegisterResourceRequest} returns this */ proto.pulumirpc.RegisterResourceRequest.prototype.setRemote = function(value) { - return jspb.Message.setProto3BooleanField(this, 21, value); + return jspb.Message.setProto3BooleanField(this, 20, value); }; diff --git a/sdk/proto/go/resource.pb.go b/sdk/proto/go/resource.pb.go index 2f47b2200..561351a20 100644 --- a/sdk/proto/go/resource.pb.go +++ b/sdk/proto/go/resource.pb.go @@ -295,7 +295,7 @@ type RegisterResourceRequest struct { CustomTimeouts *RegisterResourceRequest_CustomTimeouts `protobuf:"bytes,17,opt,name=customTimeouts,proto3" json:"customTimeouts,omitempty"` DeleteBeforeReplaceDefined bool `protobuf:"varint,18,opt,name=deleteBeforeReplaceDefined,proto3" json:"deleteBeforeReplaceDefined,omitempty"` SupportsPartialValues bool `protobuf:"varint,19,opt,name=supportsPartialValues,proto3" json:"supportsPartialValues,omitempty"` - Remote bool `protobuf:"varint,21,opt,name=remote,proto3" json:"remote,omitempty"` + Remote bool `protobuf:"varint,20,opt,name=remote,proto3" json:"remote,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -761,63 +761,63 @@ func init() { proto.RegisterFile("resource.proto", fileDescriptor_d1b72f771c35e3 var fileDescriptor_d1b72f771c35e3b8 = []byte{ // 927 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x56, 0x5f, 0x73, 0xdb, 0x44, - 0x10, 0x8f, 0xed, 0x54, 0xb1, 0x37, 0xa9, 0x13, 0x2e, 0xa9, 0x73, 0x15, 0x4c, 0x08, 0x82, 0x07, - 0xc3, 0x83, 0xd3, 0x06, 0x66, 0x1a, 0x18, 0xfe, 0xcc, 0xd0, 0x16, 0xa6, 0x0f, 0x85, 0xa2, 0x30, - 0x0c, 0x30, 0x03, 0x33, 0x17, 0x69, 0xe3, 0x8a, 0xc8, 0xba, 0xeb, 0xdd, 0x29, 0x33, 0x7e, 0x83, - 0x47, 0xbe, 0x16, 0x9f, 0x86, 0x67, 0x3e, 0x01, 0x73, 0x77, 0x92, 0xb1, 0x2c, 0x39, 0xb1, 0xcb, + 0x10, 0x8f, 0xed, 0x54, 0xb1, 0x37, 0xa9, 0x13, 0x2e, 0xc1, 0xb9, 0x0a, 0x26, 0x04, 0xc1, 0x83, + 0xe1, 0xc1, 0x69, 0x03, 0x33, 0x0d, 0x0c, 0x7f, 0x66, 0x68, 0x0b, 0xd3, 0x87, 0x42, 0x51, 0x18, + 0x06, 0x98, 0x81, 0x99, 0x8b, 0xb4, 0x71, 0x45, 0x64, 0xdd, 0xf5, 0xee, 0x94, 0x19, 0xbf, 0xc1, + 0x23, 0x5f, 0x8b, 0x4f, 0xc3, 0x33, 0x9f, 0x80, 0xb9, 0x3b, 0xc9, 0x58, 0x96, 0x9c, 0xd8, 0xed, 0xdb, 0xed, 0xee, 0xdd, 0x4a, 0xfb, 0xfb, 0xfd, 0x76, 0xef, 0xa0, 0x2f, 0x51, 0xf1, 0x5c, 0x46, - 0x38, 0x12, 0x92, 0x6b, 0x4e, 0x7a, 0x22, 0x4f, 0xf3, 0x49, 0x22, 0x45, 0xe4, 0xbf, 0x39, 0xe6, + 0x38, 0x12, 0x92, 0x6b, 0x4e, 0x7a, 0x22, 0x4f, 0xf3, 0x49, 0x22, 0x45, 0xe4, 0xbf, 0x35, 0xe6, 0x7c, 0x9c, 0xe2, 0x89, 0x0d, 0x5c, 0xe4, 0x97, 0x27, 0x38, 0x11, 0x7a, 0xea, 0xf6, 0xf9, 0x6f, - 0x2d, 0x06, 0x95, 0x96, 0x79, 0xa4, 0x8b, 0x68, 0x5f, 0x48, 0x7e, 0x9d, 0xc4, 0x28, 0x9d, 0x1d, - 0x0c, 0x61, 0x70, 0x9e, 0x0b, 0xc1, 0xa5, 0x56, 0x5f, 0x21, 0xd3, 0xb9, 0xc4, 0x10, 0x5f, 0xe5, + 0x2f, 0x06, 0x95, 0x96, 0x79, 0xa4, 0x8b, 0x68, 0x5f, 0x48, 0x7e, 0x9d, 0xc4, 0x28, 0x9d, 0x1d, + 0x0c, 0x61, 0x70, 0x9e, 0x0b, 0xc1, 0xa5, 0x56, 0x5f, 0x23, 0xd3, 0xb9, 0xc4, 0x10, 0x5f, 0xe6, 0xa8, 0x34, 0xe9, 0x43, 0x3b, 0x89, 0x69, 0xeb, 0xb8, 0x35, 0xec, 0x85, 0xed, 0x24, 0x0e, 0x3e, - 0x86, 0xc3, 0xda, 0x4e, 0x25, 0x78, 0xa6, 0x90, 0x1c, 0x01, 0xbc, 0x64, 0xaa, 0x88, 0xda, 0x23, - 0xdd, 0x70, 0xce, 0x13, 0xfc, 0xd3, 0x86, 0xfd, 0x10, 0x59, 0x1c, 0x16, 0x15, 0x2d, 0xf9, 0x04, + 0x81, 0xc3, 0xda, 0x4e, 0x25, 0x78, 0xa6, 0x90, 0x1c, 0x01, 0xbc, 0x60, 0xaa, 0x88, 0xda, 0x23, + 0xdd, 0x70, 0xce, 0x13, 0xfc, 0xdb, 0x86, 0xfd, 0x10, 0x59, 0x1c, 0x16, 0x15, 0x2d, 0xf9, 0x04, 0x21, 0xb0, 0xa9, 0xa7, 0x02, 0x69, 0xdb, 0x7a, 0xec, 0xda, 0xf8, 0x32, 0x36, 0x41, 0xda, 0x71, - 0x3e, 0xb3, 0x26, 0x03, 0xf0, 0x04, 0x93, 0x98, 0x69, 0xba, 0x69, 0xbd, 0x85, 0x45, 0x1e, 0x01, + 0x3e, 0xb3, 0x26, 0x03, 0xf0, 0x04, 0x93, 0x98, 0x69, 0xba, 0x69, 0xbd, 0x85, 0x45, 0x1e, 0x02, 0x08, 0xc9, 0x05, 0x4a, 0x9d, 0xa0, 0xa2, 0x77, 0x8e, 0x5b, 0xc3, 0xed, 0xd3, 0xc3, 0x91, 0xc3, 0x63, 0x54, 0xe2, 0x31, 0x3a, 0xb7, 0x78, 0x84, 0x73, 0x5b, 0x49, 0x00, 0x3b, 0x31, 0x0a, 0xcc, 0x62, 0xcc, 0x22, 0x73, 0xd4, 0x3b, 0xee, 0x0c, 0x7b, 0x61, 0xc5, 0x47, 0x7c, 0xe8, 0x96, 0xd8, 0xd1, 0x2d, 0xfb, 0xd9, 0x99, 0x4d, 0x28, 0x6c, 0x5d, 0xa3, 0x54, 0x09, 0xcf, 0x68, 0xd7, 0x86, - 0x4a, 0x93, 0xbc, 0x07, 0x77, 0x59, 0x14, 0xa1, 0xd0, 0xe7, 0x18, 0x49, 0xd4, 0x8a, 0xf6, 0x2c, - 0x3a, 0x55, 0x27, 0x39, 0x83, 0x43, 0x16, 0xc7, 0x89, 0x4e, 0x78, 0xc6, 0x52, 0xe7, 0xfc, 0x36, + 0x4a, 0x93, 0xbc, 0x0f, 0x77, 0x59, 0x14, 0xa1, 0xd0, 0xe7, 0x18, 0x49, 0xd4, 0x8a, 0xf6, 0x2c, + 0x3a, 0x55, 0x27, 0x39, 0x83, 0x43, 0x16, 0xc7, 0x89, 0x4e, 0x78, 0xc6, 0x52, 0xe7, 0xfc, 0x2e, 0xd7, 0x22, 0xd7, 0x8a, 0x82, 0xfd, 0x95, 0x65, 0x61, 0xf3, 0x65, 0x96, 0x26, 0x4c, 0xa1, 0xa2, 0xdb, 0x76, 0x67, 0x69, 0x06, 0x0c, 0x0e, 0xaa, 0x98, 0x17, 0x64, 0xed, 0x41, 0x27, 0x97, 0x59, - 0x81, 0xba, 0x59, 0x2e, 0xc0, 0xd6, 0x5e, 0x19, 0xb6, 0xe0, 0xef, 0x2e, 0x1c, 0x86, 0x38, 0x4e, + 0x81, 0xba, 0x59, 0x2e, 0xc0, 0xd6, 0x5e, 0x19, 0xb6, 0xe0, 0x9f, 0x2e, 0x1c, 0x86, 0x38, 0x4e, 0x94, 0x46, 0xb9, 0xc8, 0x6d, 0xc9, 0x65, 0xab, 0x81, 0xcb, 0x76, 0x23, 0x97, 0x9d, 0x0a, 0x97, 0x03, 0xf0, 0xa2, 0x5c, 0x69, 0x3e, 0xb1, 0x1c, 0x77, 0xc3, 0xc2, 0x22, 0x27, 0xe0, 0xf1, 0x8b, - 0xdf, 0x30, 0xd2, 0xb7, 0xf1, 0x5b, 0x6c, 0x33, 0x08, 0x99, 0x90, 0x39, 0xe1, 0xd9, 0x4c, 0xa5, - 0x59, 0x63, 0x7d, 0xeb, 0x16, 0xd6, 0xbb, 0x0b, 0xac, 0x0b, 0x38, 0x28, 0xc0, 0x98, 0x3e, 0x99, - 0xcf, 0xd3, 0x3b, 0xee, 0x0c, 0xb7, 0x4f, 0x3f, 0x1d, 0xcd, 0x1a, 0x76, 0xb4, 0x04, 0xa4, 0xd1, - 0x8b, 0x86, 0xe3, 0x4f, 0x33, 0x2d, 0xa7, 0x61, 0x63, 0x66, 0xf2, 0x00, 0xf6, 0x63, 0x4c, 0x51, - 0xe3, 0x97, 0x78, 0xc9, 0x4d, 0x03, 0x8a, 0x94, 0x45, 0x48, 0xc1, 0xd6, 0xd5, 0x14, 0x9a, 0x57, - 0xe6, 0x76, 0x4d, 0x99, 0xc9, 0x38, 0xe3, 0x12, 0x1f, 0xbf, 0x64, 0xd9, 0x18, 0x15, 0xdd, 0xb1, + 0xdf, 0x31, 0xd2, 0xb7, 0xf1, 0x5b, 0x6c, 0x33, 0x08, 0x99, 0x90, 0x39, 0xe1, 0xd9, 0x4c, 0xa5, + 0x59, 0x63, 0x7d, 0xeb, 0x16, 0xd6, 0xbb, 0x0b, 0xac, 0x0b, 0x38, 0x28, 0xc0, 0x98, 0x3e, 0x9e, + 0xcf, 0xd3, 0x3b, 0xee, 0x0c, 0xb7, 0x4f, 0x3f, 0x1b, 0xcd, 0x1a, 0x76, 0xb4, 0x04, 0xa4, 0xd1, + 0xf3, 0x86, 0xe3, 0x4f, 0x32, 0x2d, 0xa7, 0x61, 0x63, 0x66, 0x72, 0x1f, 0xf6, 0x63, 0x4c, 0x51, + 0xe3, 0x57, 0x78, 0xc9, 0x4d, 0x03, 0x8a, 0x94, 0x45, 0x48, 0xc1, 0xd6, 0xd5, 0x14, 0x9a, 0x57, + 0xe6, 0x76, 0x4d, 0x99, 0xc9, 0x38, 0xe3, 0x12, 0x1f, 0xbd, 0x60, 0xd9, 0x18, 0x15, 0xdd, 0xb1, 0xe5, 0x57, 0x9d, 0x75, 0xfd, 0xde, 0x5d, 0x53, 0xbf, 0xfd, 0x95, 0xf5, 0xbb, 0x5b, 0xd1, 0xaf, - 0x41, 0x3e, 0x99, 0x98, 0xf1, 0xf1, 0x2c, 0xa6, 0x7b, 0x0e, 0xf9, 0xd2, 0x26, 0x3f, 0x41, 0xdf, - 0xc9, 0xe1, 0xfb, 0x64, 0x82, 0xdc, 0x7c, 0xe6, 0x0d, 0x2b, 0x86, 0x87, 0x2b, 0x60, 0xfe, 0xb8, - 0x72, 0x30, 0x5c, 0x48, 0x44, 0x3e, 0x07, 0xbf, 0x01, 0xc7, 0x27, 0x78, 0x99, 0x64, 0x18, 0x53, - 0x62, 0xab, 0xbf, 0x61, 0x07, 0xf9, 0x08, 0xee, 0xa9, 0x62, 0x4c, 0xbe, 0x60, 0x52, 0x27, 0x2c, - 0xfd, 0x81, 0xa5, 0x39, 0x2a, 0xba, 0x6f, 0x8f, 0x36, 0x07, 0x8d, 0xda, 0x25, 0x4e, 0xb8, 0x46, - 0x7a, 0xcf, 0xa9, 0xdd, 0x59, 0xfe, 0x07, 0x70, 0xd0, 0xa4, 0x11, 0xd3, 0x49, 0xb9, 0xcc, 0x14, - 0x6d, 0x59, 0xcc, 0xec, 0xda, 0xff, 0x11, 0xfa, 0xd5, 0xda, 0x6c, 0x0f, 0x49, 0x64, 0xba, 0xec, + 0x41, 0x3e, 0x99, 0x98, 0xf1, 0xf1, 0x34, 0xa6, 0x7b, 0x0e, 0xf9, 0xd2, 0x26, 0x3f, 0x43, 0xdf, + 0xc9, 0xe1, 0x87, 0x64, 0x82, 0xdc, 0x7c, 0xe6, 0x0d, 0x2b, 0x86, 0x07, 0x2b, 0x60, 0xfe, 0xa8, + 0x72, 0x30, 0x5c, 0x48, 0x44, 0xbe, 0x00, 0xbf, 0x01, 0xc7, 0xc7, 0x78, 0x99, 0x64, 0x18, 0x53, + 0x62, 0xab, 0xbf, 0x61, 0x07, 0xf9, 0x18, 0xde, 0x54, 0xc5, 0x98, 0x7c, 0xce, 0xa4, 0x4e, 0x58, + 0xfa, 0x23, 0x4b, 0x73, 0x54, 0x74, 0xdf, 0x1e, 0x6d, 0x0e, 0x1a, 0xb5, 0x4b, 0x9c, 0x70, 0x8d, + 0xf4, 0xc0, 0xa9, 0xdd, 0x59, 0xfe, 0x87, 0x70, 0xd0, 0xa4, 0x11, 0xd3, 0x49, 0xb9, 0xcc, 0x14, + 0x6d, 0x59, 0xcc, 0xec, 0xda, 0xff, 0x09, 0xfa, 0xd5, 0xda, 0x6c, 0x0f, 0x49, 0x64, 0xba, 0xec, 0xc2, 0xc2, 0x32, 0xfe, 0x5c, 0xc4, 0xc6, 0xef, 0x3a, 0xb1, 0xb0, 0x8c, 0xdf, 0x55, 0x56, 0xf6, - 0xa2, 0xb3, 0xfc, 0xdf, 0x5b, 0x70, 0x7f, 0xa9, 0x54, 0xcd, 0x40, 0xb9, 0xc2, 0x69, 0x39, 0x50, - 0xae, 0x70, 0x4a, 0x9e, 0xc3, 0x9d, 0x6b, 0x53, 0x57, 0x31, 0x4b, 0x1e, 0xbd, 0x66, 0x27, 0x84, - 0x2e, 0xcb, 0x27, 0xed, 0xb3, 0x56, 0xf0, 0x57, 0x07, 0x68, 0xfd, 0xec, 0xd2, 0x91, 0xe6, 0x6e, - 0x96, 0xf6, 0xec, 0x66, 0xf9, 0x6f, 0x6a, 0x74, 0x56, 0x9b, 0x1a, 0x03, 0xf0, 0x94, 0x66, 0x17, - 0x29, 0x96, 0xe3, 0xc7, 0x59, 0x46, 0xaf, 0x6e, 0x65, 0xee, 0x17, 0xab, 0xd7, 0xc2, 0x24, 0xaf, - 0x96, 0x4c, 0x03, 0xcf, 0x4e, 0x83, 0xcf, 0x6e, 0xc4, 0xc0, 0xd5, 0xb1, 0xee, 0x38, 0x58, 0x4b, - 0x1d, 0x7f, 0xac, 0xc9, 0xe1, 0x37, 0x55, 0x0e, 0xcf, 0x5e, 0xf7, 0xff, 0xe7, 0x49, 0x44, 0x38, - 0x5a, 0x3c, 0x5b, 0xcc, 0x81, 0xf2, 0xd6, 0xa8, 0x33, 0xf9, 0x10, 0xb6, 0x78, 0x31, 0x4a, 0x6e, - 0xb9, 0x99, 0xca, 0x7d, 0xa7, 0x7f, 0x6e, 0xc2, 0x6e, 0x99, 0xff, 0x39, 0xcf, 0x12, 0xcd, 0x25, - 0xf9, 0x19, 0x76, 0x17, 0x5e, 0x2f, 0xe4, 0x9d, 0xb9, 0x92, 0x9a, 0xdf, 0x40, 0x7e, 0x70, 0xd3, - 0x16, 0x57, 0x74, 0xb0, 0x41, 0xbe, 0x00, 0xef, 0x59, 0x76, 0xcd, 0xaf, 0x90, 0xd0, 0xb9, 0xfd, - 0xce, 0x55, 0x66, 0xba, 0xdf, 0x10, 0x99, 0x25, 0xf8, 0x1a, 0x76, 0xce, 0xb5, 0x44, 0x36, 0xf9, - 0x5f, 0x69, 0x1e, 0xb4, 0xc8, 0x77, 0xb0, 0x33, 0x7f, 0xe7, 0x93, 0xa3, 0x0a, 0x6b, 0xb5, 0x07, - 0x98, 0xff, 0xf6, 0xd2, 0xf8, 0xec, 0xdf, 0x7e, 0x81, 0xbd, 0x45, 0xce, 0x48, 0x70, 0x7b, 0x43, - 0xfb, 0xef, 0xae, 0x20, 0x98, 0x60, 0x83, 0xfc, 0x5a, 0x7f, 0x41, 0x94, 0x57, 0xc3, 0xfb, 0x37, - 0x64, 0xa8, 0xca, 0xc6, 0x1f, 0xd4, 0x34, 0xf1, 0xd4, 0xbc, 0x88, 0x83, 0x8d, 0x0b, 0xcf, 0x7a, - 0x3e, 0xfc, 0x37, 0x00, 0x00, 0xff, 0xff, 0x7a, 0x67, 0xe8, 0xd7, 0x4e, 0x0b, 0x00, 0x00, + 0xa2, 0xb3, 0xfc, 0x3f, 0x5a, 0x70, 0x6f, 0xa9, 0x54, 0xcd, 0x40, 0xb9, 0xc2, 0x69, 0x39, 0x50, + 0xae, 0x70, 0x4a, 0x9e, 0xc1, 0x9d, 0x6b, 0x53, 0x57, 0x31, 0x4b, 0x1e, 0xbe, 0x62, 0x27, 0x84, + 0x2e, 0xcb, 0xa7, 0xed, 0xb3, 0x56, 0xf0, 0x77, 0x07, 0x68, 0xfd, 0xec, 0xd2, 0x91, 0xe6, 0x6e, + 0x96, 0xf6, 0xec, 0x66, 0xf9, 0x7f, 0x6a, 0x74, 0x56, 0x9b, 0x1a, 0x03, 0xf0, 0x94, 0x66, 0x17, + 0x29, 0x96, 0xe3, 0xc7, 0x59, 0x46, 0xaf, 0x6e, 0x65, 0xee, 0x17, 0xab, 0xd7, 0xc2, 0x24, 0x2f, + 0x97, 0x4c, 0x03, 0xcf, 0x4e, 0x83, 0xcf, 0x6f, 0xc4, 0xc0, 0xd5, 0xb1, 0xee, 0x38, 0x58, 0x4b, + 0x1d, 0x7f, 0xae, 0xc9, 0xe1, 0xb7, 0x55, 0x0e, 0xcf, 0x5e, 0xf5, 0xff, 0xe7, 0x49, 0x44, 0x38, + 0x5a, 0x3c, 0x5b, 0xcc, 0x81, 0xf2, 0xd6, 0xa8, 0x33, 0xf9, 0x00, 0xb6, 0x78, 0x31, 0x4a, 0x6e, + 0xb9, 0x99, 0xca, 0x7d, 0xa7, 0x7f, 0x6d, 0xc2, 0x6e, 0x99, 0xff, 0x19, 0xcf, 0x12, 0xcd, 0x25, + 0xf9, 0x05, 0x76, 0x17, 0x5e, 0x2f, 0xe4, 0xdd, 0xb9, 0x92, 0x9a, 0xdf, 0x40, 0x7e, 0x70, 0xd3, + 0x16, 0x57, 0x74, 0xb0, 0x41, 0xbe, 0x04, 0xef, 0x69, 0x76, 0xcd, 0xaf, 0x90, 0xd0, 0xb9, 0xfd, + 0xce, 0x55, 0x66, 0xba, 0xd7, 0x10, 0x99, 0x25, 0xf8, 0x06, 0x76, 0xce, 0xb5, 0x44, 0x36, 0x79, + 0xad, 0x34, 0xf7, 0x5b, 0xe4, 0x7b, 0xd8, 0x99, 0xbf, 0xf3, 0xc9, 0x51, 0x85, 0xb5, 0xda, 0x03, + 0xcc, 0x7f, 0x67, 0x69, 0x7c, 0xf6, 0x6f, 0xbf, 0xc2, 0xde, 0x22, 0x67, 0x24, 0xb8, 0xbd, 0xa1, + 0xfd, 0xf7, 0x56, 0x10, 0x4c, 0xb0, 0x41, 0x7e, 0xab, 0xbf, 0x20, 0xca, 0xab, 0xe1, 0x83, 0x1b, + 0x32, 0x54, 0x65, 0xe3, 0x0f, 0x6a, 0x9a, 0x78, 0x62, 0x5e, 0xc4, 0xc1, 0xc6, 0x85, 0x67, 0x3d, + 0x1f, 0xfd, 0x17, 0x00, 0x00, 0xff, 0xff, 0xfe, 0xbf, 0x6d, 0x72, 0x4e, 0x0b, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/sdk/python/.pylintrc b/sdk/python/.pylintrc index 7af4d566e..849b3307c 100644 --- a/sdk/python/.pylintrc +++ b/sdk/python/.pylintrc @@ -160,7 +160,8 @@ disable=print-statement, no-self-use, unused-import, unsubscriptable-object, - line-too-long + line-too-long, + too-many-lines # Enable the message, report, category or checker with the given id(s). You can diff --git a/sdk/python/lib/pulumi/resource.py b/sdk/python/lib/pulumi/resource.py index 4dc83e162..0c9578932 100644 --- a/sdk/python/lib/pulumi/resource.py +++ b/sdk/python/lib/pulumi/resource.py @@ -13,6 +13,9 @@ # limitations under the License. """The Resource module, containing all resource-related definitions.""" + +import asyncio + from typing import Optional, List, Any, Mapping, Union, Callable, TYPE_CHECKING, cast import copy @@ -594,7 +597,9 @@ class Resource: name: str, custom: bool, props: Optional['Inputs'] = None, - opts: Optional[ResourceOptions] = None) -> None: + opts: Optional[ResourceOptions] = None, + remote: bool = False, + dependency: bool = False) -> None: """ :param str t: The type of this resource. :param str name: The name of this resource. @@ -602,7 +607,15 @@ class Resource: :param Optional[dict] props: An optional list of input properties to use as inputs for the resource. :param Optional[ResourceOptions] opts: Optional set of :class:`pulumi.ResourceOptions` to use for this resource. + :param bool remote: True if this is a remote component resource. + :param bool dependency: True if this is a synthetic resource used internally for dependency tracking. """ + + if dependency: + self._protect = False + self._providers = {} + return + if props is None: props = {} if not t: @@ -699,13 +712,13 @@ class Resource: alias, name, t, opts.parent)) if opts.id is not None: - # If this resource already exists, read its state rather than registering it anew. + # If this is a custom resource that already exists, read its state from the provider. if not custom: raise Exception( "Cannot read an existing resource unless it has a custom provider") read_resource(cast('CustomResource', self), t, name, props, opts) else: - register_resource(self, t, name, custom, props, opts) + register_resource(self, t, name, custom, remote, DependencyResource, props, opts) @property def urn(self) -> 'Output[str]': @@ -790,15 +803,17 @@ class CustomResource(Resource): t: str, name: str, props: Optional[dict] = None, - opts: Optional[ResourceOptions] = None) -> None: + opts: Optional[ResourceOptions] = None, + dependency: bool = False) -> None: """ :param str t: The type of this resource. :param str name: The name of this resource. :param Optional[dict] props: An optional list of input properties to use as inputs for the resource. :param Optional[ResourceOptions] opts: Optional set of :class:`pulumi.ResourceOptions` to use for this resource. + :param bool dependency: True if this is a synthetic resource used internally for dependency tracking. """ - Resource.__init__(self, t, name, True, props, opts) + Resource.__init__(self, t, name, True, props, opts, False, dependency) self.__pulumi_type = t @property @@ -821,16 +836,18 @@ class ComponentResource(Resource): t: str, name: str, props: Optional[dict] = None, - opts: Optional[ResourceOptions] = None) -> None: + opts: Optional[ResourceOptions] = None, + remote: bool = False) -> None: """ :param str t: The type of this resource. :param str name: The name of this resource. :param Optional[dict] props: An optional list of input properties to use as inputs for the resource. :param Optional[ResourceOptions] opts: Optional set of :class:`pulumi.ResourceOptions` to use for this resource. + :param bool remote: True if this is a remote component resource. """ - Resource.__init__(self, t, name, False, props, opts) - self.id = None + Resource.__init__(self, t, name, False, props, opts, remote) + self.__dict__["id"] = None def register_outputs(self, outputs): """ @@ -858,13 +875,15 @@ class ProviderResource(CustomResource): pkg: str, name: str, props: Optional[dict] = None, - opts: Optional[ResourceOptions] = None) -> None: + opts: Optional[ResourceOptions] = None, + dependency: bool = False) -> None: """ :param str pkg: The package type of this provider resource. :param str name: The name of this resource. :param Optional[dict] props: An optional list of input properties to use as inputs for the resource. :param Optional[ResourceOptions] opts: Optional set of :class:`pulumi.ResourceOptions` to use for this resource. + :param bool dependency: True if this is a synthetic resource used internally for dependency tracking. """ if opts is not None and opts.provider is not None: @@ -872,10 +891,63 @@ class ProviderResource(CustomResource): "Explicit providers may not be used with provider resources") # Provider resources are given a well-known type, prefixed with "pulumi:providers". CustomResource.__init__( - self, f"pulumi:providers:{pkg}", name, props, opts) + self, f"pulumi:providers:{pkg}", name, props, opts, dependency) self.package = pkg +class DependencyResource(CustomResource): + """ + A DependencyResource is a resource that is used to indicate that an Output has a dependency on a particular + resource. These resources are only created when dealing with remote component resources. + """ + + def __init__(self, urn: str) -> None: + super().__init__(t="", name="", props={}, opts=None, dependency=True) + + from . import Output # pylint: disable=import-outside-toplevel + + urn_future: asyncio.Future[str] = asyncio.Future() + urn_known: asyncio.Future[bool] = asyncio.Future() + urn_secret: asyncio.Future[bool] = asyncio.Future() + urn_future.set_result(urn) + urn_known.set_result(True) + urn_secret.set_result(False) + self.__dict__["urn"] = Output({self}, urn_future, urn_known, urn_secret) + + +class DependencyProviderResource(ProviderResource): + """ + A DependencyProviderResource is a resource that is used by the provider SDK as a stand-in for a provider that + is only used for its reference. Its only valid properties are its URN and ID. + """ + + def __init__(self, ref: str) -> None: + super().__init__(pkg="", name="", props={}, opts=None, dependency=True) + + # Parse the URN and ID out of the provider reference. + last_sep = ref.rindex("::") + ref_urn = ref[:last_sep] + ref_id = ref[last_sep+2:] + + from . import Output # pylint: disable=import-outside-toplevel + + urn_future: asyncio.Future[str] = asyncio.Future() + urn_known: asyncio.Future[bool] = asyncio.Future() + urn_secret: asyncio.Future[bool] = asyncio.Future() + urn_future.set_result(ref_urn) + urn_known.set_result(True) + urn_secret.set_result(False) + self.__dict__["urn"] = Output({self}, urn_future, urn_known, urn_secret) + + id_future: asyncio.Future[str] = asyncio.Future() + id_known: asyncio.Future[bool] = asyncio.Future() + id_secret: asyncio.Future[bool] = asyncio.Future() + id_future.set_result(ref_id) + id_known.set_result(True) + id_secret.set_result(False) + self.__dict__["id"] = Output({self}, id_future, id_known, id_secret) + + def export(name: str, value: Any): """ Exports a named stack output. diff --git a/sdk/python/lib/pulumi/runtime/proto/resource_pb2.py b/sdk/python/lib/pulumi/runtime/proto/resource_pb2.py index 701c26cf0..0a2b41443 100644 --- a/sdk/python/lib/pulumi/runtime/proto/resource_pb2.py +++ b/sdk/python/lib/pulumi/runtime/proto/resource_pb2.py @@ -21,7 +21,7 @@ DESCRIPTOR = _descriptor.FileDescriptor( package='pulumirpc', syntax='proto3', serialized_options=None, - serialized_pb=b'\n\x0eresource.proto\x12\tpulumirpc\x1a\x1bgoogle/protobuf/empty.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a\x0eprovider.proto\"$\n\x16SupportsFeatureRequest\x12\n\n\x02id\x18\x01 \x01(\t\"-\n\x17SupportsFeatureResponse\x12\x12\n\nhasSupport\x18\x01 \x01(\x08\"\xfc\x01\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\x0f\n\x07\x61liases\x18\x0b \x03(\t\"P\n\x14ReadResourceResponse\x12\x0b\n\x03urn\x18\x01 \x01(\t\x12+\n\nproperties\x18\x02 \x01(\x0b\x32\x17.google.protobuf.Struct\"\xaf\x06\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\x0f\n\x07\x61liases\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\x15 \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\"\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.Struct2\x89\x04\n\x0fResourceMonitor\x12Z\n\x0fSupportsFeature\x12!.pulumirpc.SupportsFeatureRequest\x1a\".pulumirpc.SupportsFeatureResponse\"\x00\x12?\n\x06Invoke\x12\x18.pulumirpc.InvokeRequest\x1a\x19.pulumirpc.InvokeResponse\"\x00\x12G\n\x0cStreamInvoke\x12\x18.pulumirpc.InvokeRequest\x1a\x19.pulumirpc.InvokeResponse\"\x00\x30\x01\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\x62\x06proto3' + serialized_pb=b'\n\x0eresource.proto\x12\tpulumirpc\x1a\x1bgoogle/protobuf/empty.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a\x0eprovider.proto\"$\n\x16SupportsFeatureRequest\x12\n\n\x02id\x18\x01 \x01(\t\"-\n\x17SupportsFeatureResponse\x12\x12\n\nhasSupport\x18\x01 \x01(\x08\"\xfc\x01\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\x0f\n\x07\x61liases\x18\x0b \x03(\t\"P\n\x14ReadResourceResponse\x12\x0b\n\x03urn\x18\x01 \x01(\t\x12+\n\nproperties\x18\x02 \x01(\x0b\x32\x17.google.protobuf.Struct\"\xaf\x06\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\x0f\n\x07\x61liases\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\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\"\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.Struct2\x89\x04\n\x0fResourceMonitor\x12Z\n\x0fSupportsFeature\x12!.pulumirpc.SupportsFeatureRequest\x1a\".pulumirpc.SupportsFeatureResponse\"\x00\x12?\n\x06Invoke\x12\x18.pulumirpc.InvokeRequest\x1a\x19.pulumirpc.InvokeResponse\"\x00\x12G\n\x0cStreamInvoke\x12\x18.pulumirpc.InvokeRequest\x1a\x19.pulumirpc.InvokeResponse\"\x00\x30\x01\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\x62\x06proto3' , dependencies=[google_dot_protobuf_dot_empty__pb2.DESCRIPTOR,google_dot_protobuf_dot_struct__pb2.DESCRIPTOR,provider__pb2.DESCRIPTOR,]) @@ -482,7 +482,7 @@ _REGISTERRESOURCEREQUEST = _descriptor.Descriptor( serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='remote', full_name='pulumirpc.RegisterResourceRequest.remote', index=19, - number=21, type=8, cpp_type=7, label=1, + number=20, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, diff --git a/sdk/python/lib/pulumi/runtime/resource.py b/sdk/python/lib/pulumi/runtime/resource.py index 01fc97af9..c0db85273 100644 --- a/sdk/python/lib/pulumi/runtime/resource.py +++ b/sdk/python/lib/pulumi/runtime/resource.py @@ -228,7 +228,7 @@ def read_resource(res: 'CustomResource', ty: str, name: str, props: 'Inputs', op def do_rpc_call(): if monitor is None: # If no monitor is available, we'll need to fake up a response, for testing. - return RegisterResponse(mock_urn, None, resolver.serialized_props) + return RegisterResponse(mock_urn, None, resolver.serialized_props, None) # If there is a monitor available, make the true RPC request to the engine. try: @@ -256,19 +256,26 @@ def read_resource(res: 'CustomResource', ty: str, name: str, props: 'Inputs', op log.debug(f"resource read successful: ty={ty}, urn={resp.urn}") resolve_urn(resp.urn) resolve_id(resolved_id, True, None) # Read IDs are always known. - await rpc.resolve_outputs(res, resolver.serialized_props, resp.properties, resolvers) + await rpc.resolve_outputs(res, resolver.serialized_props, resp.properties, {}, resolvers) asyncio.ensure_future(RPC_MANAGER.do_rpc("read resource", do_read)()) -def register_resource(res: 'Resource', ty: str, name: str, custom: bool, props: 'Inputs', opts: Optional['ResourceOptions']) -> None: +def register_resource(res: 'Resource', + ty: str, + name: str, + custom: bool, + remote: bool, + new_dependency: Callable[[str], 'Resource'], + props: 'Inputs', + opts: Optional['ResourceOptions']) -> None: """ Registers a new resource object with a given type t and name. It returns the auto-generated URN and the ID that will resolve after the deployment has completed. All properties will be initialized to property objects that the registration operation will resolve at the right time (or remain unresolved for deployments). """ - log.debug(f"registering resource: ty={ty}, name={name}, custom={custom}") + log.debug(f"registering resource: ty={ty}, name={name}, custom={custom}, remote={remote}") monitor = settings.get_monitor() from .. import Output # pylint: disable=import-outside-toplevel @@ -381,6 +388,7 @@ def register_resource(res: 'Resource', ty: str, name: str, custom: bool, props: customTimeouts=custom_timeouts, aliases=resolver.aliases, supportsPartialValues=True, + remote=remote, ) from ..resource import create_urn # pylint: disable=import-outside-toplevel @@ -389,7 +397,7 @@ def register_resource(res: 'Resource', ty: str, name: str, custom: bool, props: def do_rpc_call(): if monitor is None: # If no monitor is available, we'll need to fake up a response, for testing. - return RegisterResponse(mock_urn, None, resolver.serialized_props) + return RegisterResponse(mock_urn, None, resolver.serialized_props, None) # If there is a monitor available, make the true RPC request to the engine. try: @@ -423,7 +431,15 @@ def register_resource(res: 'Resource', ty: str, name: str, custom: bool, props: is_known = bool(resp.id) resolve_id(resp.id, is_known, None) - await rpc.resolve_outputs(res, resolver.serialized_props, resp.object, resolvers) + deps = {} + rpc_deps = resp.propertyDependencies + if rpc_deps: + for k, v in rpc_deps.items(): + urns = list(v.urns) + deps[k] = set(map(new_dependency, urns)) + + + await rpc.resolve_outputs(res, resolver.serialized_props, resp.object, deps, resolvers) asyncio.ensure_future(RPC_MANAGER.do_rpc( "register resource", do_register)()) @@ -464,13 +480,26 @@ def register_resource_outputs(res: 'Resource', outputs: 'Union[Inputs, Output[In "register resource outputs", do_register_resource_outputs)()) +class PropertyDependencies: + urns: List[str] + + def __init__(self, urns: List[str]): + self.urns = urns + + class RegisterResponse: urn: str id: str object: struct_pb2.Struct + propertyDependencies: Dict[str, PropertyDependencies] # pylint: disable=redefined-builtin - def __init__(self, urn: str, id: str, object: struct_pb2.Struct): + def __init__(self, + urn: str, + id: str, + object: struct_pb2.Struct, + propertyDependencies: Dict[str, PropertyDependencies]): self.urn = urn self.id = id self.object = object + self.propertyDependencies = propertyDependencies diff --git a/sdk/python/lib/pulumi/runtime/rpc.py b/sdk/python/lib/pulumi/runtime/rpc.py index b8262f838..7ed172aec 100644 --- a/sdk/python/lib/pulumi/runtime/rpc.py +++ b/sdk/python/lib/pulumi/runtime/rpc.py @@ -20,7 +20,7 @@ import asyncio from collections import abc import functools import inspect -from typing import List, Any, Callable, Dict, Mapping, Optional, Sequence, TYPE_CHECKING, cast +from typing import List, Any, Callable, Dict, Mapping, Optional, Sequence, Set, TYPE_CHECKING, cast from google.protobuf import struct_pb2 import six @@ -329,7 +329,7 @@ def deserialize_property(value: Any, keep_unknowns: Optional[bool] = None) -> An return value -Resolver = Callable[[Any, bool, bool, Optional[Exception]], None] +Resolver = Callable[[Any, bool, bool, Optional[Set['Resource']], Optional[Exception]], None] """ A Resolver is a function that takes four arguments: 1. A value, which represents the "resolved" value of a particular output (from the engine) @@ -355,14 +355,24 @@ def transfer_properties(res: 'Resource', props: 'Inputs') -> Dict[str, Resolver] resolve_value: 'asyncio.Future' = asyncio.Future() resolve_is_known: 'asyncio.Future' = asyncio.Future() resolve_is_secret: 'asyncio.Future' = asyncio.Future() + resolve_deps: 'asyncio.Future' = asyncio.Future() - def do_resolve(value_fut: 'asyncio.Future', + def do_resolve(r: 'Resource', + value_fut: 'asyncio.Future', known_fut: 'asyncio.Future[bool]', secret_fut: 'asyncio.Future[bool]', + deps_fut: 'asyncio.Future[Set[Resource]]', value: Any, is_known: bool, is_secret: bool, + deps: Set['Resource'], failed: Optional[Exception]): + + # Create a union of deps and the resource. + deps_union = set(deps) if deps else set() + deps_union.add(r) + deps_fut.set_result(deps_union) + # Was an exception provided? If so, this is an abnormal (exceptional) resolution. Resolve the futures # using set_exception so that any attempts to wait for their resolution will also fail. if failed is not None: @@ -378,8 +388,8 @@ def transfer_properties(res: 'Resource', props: 'Inputs') -> Dict[str, Resolver] # name before translation. When properties are returned from the engine, we must first translate the name # using res.translate_output_property and then use *that* name to index into the resolvers table. log.debug(f"adding resolver {name}") - resolvers[name] = functools.partial(do_resolve, resolve_value, resolve_is_known, resolve_is_secret) - res.__dict__[name] = Output({res}, resolve_value, resolve_is_known, resolve_is_secret) + resolvers[name] = functools.partial(do_resolve, res, resolve_value, resolve_is_known, resolve_is_secret, resolve_deps) + res.__dict__[name] = Output(resolve_deps, resolve_value, resolve_is_known, resolve_is_secret) return resolvers @@ -497,6 +507,7 @@ def contains_unknowns(val: Any) -> bool: async def resolve_outputs(res: 'Resource', serialized_props: struct_pb2.Struct, outputs: struct_pb2.Struct, + deps: Mapping[str, Set['Resource']], resolvers: Dict[str, Resolver]): # Produce a combined set of property states, starting with inputs and then applying @@ -559,18 +570,18 @@ async def resolve_outputs(res: 'Resource', if not settings.is_dry_run(): # normal 'pulumi up'. resolve the output with the value we got back # from the engine. That output can always run its .apply calls. - resolve(value, True, is_secret, None) + resolve(value, True, is_secret, deps.get(key), None) else: # We're previewing. If the engine was able to give us a reasonable value back, # then use it. Otherwise, inform the Output that the value isn't known. - resolve(value, value is not None, is_secret, None) + resolve(value, value is not None, is_secret, deps.get(key), None) # `allProps` may not have contained a value for every resolver: for example, optional outputs may not be present. # We will resolve all of these values as `None`, and will mark the value as known if we are not running a # preview. for key, resolve in resolvers.items(): if key not in all_properties: - resolve(None, not settings.is_dry_run(), False, None) + resolve(None, not settings.is_dry_run(), False, deps.get(key), None) def resolve_outputs_due_to_exception(resolvers: Dict[str, Resolver], exn: Exception): @@ -583,4 +594,4 @@ def resolve_outputs_due_to_exception(resolvers: Dict[str, Resolver], exn: Except """ for key, resolve in resolvers.items(): log.debug(f"sending exception to resolver for {key}") - resolve(None, False, False, exn) + resolve(None, False, False, None, exn) diff --git a/tests/integration/construct_component/nodejs/component.ts b/tests/integration/construct_component/nodejs/component.ts index ae4d51325..a98c770d8 100644 --- a/tests/integration/construct_component/nodejs/component.ts +++ b/tests/integration/construct_component/nodejs/component.ts @@ -1,3 +1,5 @@ +// Copyright 2016-2020, Pulumi Corporation. All rights reserved. + import * as pulumi from "@pulumi/pulumi"; interface ComponentArgs { diff --git a/tests/integration/construct_component/nodejs/index.ts b/tests/integration/construct_component/nodejs/index.ts index a2ffe6d59..863a1fda9 100644 --- a/tests/integration/construct_component/nodejs/index.ts +++ b/tests/integration/construct_component/nodejs/index.ts @@ -1,4 +1,4 @@ -// Copyright 2016-2018, Pulumi Corporation. All rights reserved. +// Copyright 2016-2020, Pulumi Corporation. All rights reserved. import { Component } from "./component"; diff --git a/tests/integration/construct_component/python/.gitignore b/tests/integration/construct_component/python/.gitignore new file mode 100644 index 000000000..3f47d8e79 --- /dev/null +++ b/tests/integration/construct_component/python/.gitignore @@ -0,0 +1,5 @@ +*.pyc +/.pulumi/ +/dist/ +/*.egg-info +venv/ diff --git a/tests/integration/construct_component/python/Pulumi.yaml b/tests/integration/construct_component/python/Pulumi.yaml new file mode 100644 index 000000000..a332db434 --- /dev/null +++ b/tests/integration/construct_component/python/Pulumi.yaml @@ -0,0 +1,3 @@ +name: construct_component_py +description: A program that constructs remote component resources. +runtime: python diff --git a/tests/integration/construct_component/python/__main__.py b/tests/integration/construct_component/python/__main__.py new file mode 100644 index 000000000..de891d5c5 --- /dev/null +++ b/tests/integration/construct_component/python/__main__.py @@ -0,0 +1,7 @@ +# Copyright 2016-2018, Pulumi Corporation. All rights reserved. + +from component import Component + +component_a = Component("a", echo=42) +component_b = Component("b", echo=component_a.echo) +component_c = Component("c", echo=component_a.childId) diff --git a/tests/integration/construct_component/python/component.py b/tests/integration/construct_component/python/component.py new file mode 100644 index 000000000..d48f59455 --- /dev/null +++ b/tests/integration/construct_component/python/component.py @@ -0,0 +1,15 @@ +# Copyright 2016-2020, Pulumi Corporation. All rights reserved. + +from typing import Any, Optional + +import pulumi + +class Component(pulumi.ComponentResource): + echo: pulumi.Output[Any] + childId: pulumi.Output[str] + + def __init__(self, name: str, echo: pulumi.Input[Any], opts: Optional[pulumi.ResourceOptions] = None): + props = dict() + props["echo"] = echo + props["childId"] = None + super().__init__("testcomponent:index:Component", name, props, opts, True) diff --git a/tests/integration/construct_component/python/requirements.txt b/tests/integration/construct_component/python/requirements.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/integration/integration_nodejs_test.go b/tests/integration/integration_nodejs_test.go index ad3ec8a58..ab7e0804c 100644 --- a/tests/integration/integration_nodejs_test.go +++ b/tests/integration/integration_nodejs_test.go @@ -602,24 +602,6 @@ func TestLargeResourceNode(t *testing.T) { }) } -func testComponentPathEnv() (string, error) { - cwd, err := os.Getwd() - if err != nil { - return "", err - } - absCwd, err := filepath.Abs(cwd) - if err != nil { - return "", err - } - pluginDir := filepath.Join(absCwd, "construct_component", "testcomponent") - - pathSeparator := ":" - if runtime.GOOS == "windows" { - pathSeparator = ";" - } - return "PATH=" + os.Getenv("PATH") + pathSeparator + pluginDir, nil -} - // Test remote component construction in Node. func TestConstructNode(t *testing.T) { pathEnv, err := testComponentPathEnv() diff --git a/tests/integration/integration_python_test.go b/tests/integration/integration_python_test.go index 9e1acd92b..0ed324e74 100644 --- a/tests/integration/integration_python_test.go +++ b/tests/integration/integration_python_test.go @@ -341,3 +341,59 @@ func TestPythonPylint(t *testing.T) { } integration.ProgramTest(t, opts) } + +// Test remote component construction in Python. +func TestConstructPython(t *testing.T) { + pathEnv, err := testComponentPathEnv() + if err != nil { + t.Fatalf("failed to build test component PATH: %v", err) + } + + // TODO[pulumi/pulumi#5455]: Dynamic providers fail to load when used from multi-lang components. + // Until we've addressed this, set PULUMI_TEST_YARN_LINK_PULUMI, which tells the integration test + // module to run `yarn install && yarn link @pulumi/pulumi` in the Python program's directory, allowing + // the Node.js dynamic provider plugin to load. + // When the underlying issue has been fixed, the use of this environment variable inside the integration + // test module should be removed. + const testYarnLinkPulumiEnv = "PULUMI_TEST_YARN_LINK_PULUMI=true" + + var opts *integration.ProgramTestOptions + opts = &integration.ProgramTestOptions{ + Env: []string{pathEnv, testYarnLinkPulumiEnv}, + Dir: filepath.Join("construct_component", "python"), + Dependencies: []string{ + filepath.Join("..", "..", "sdk", "python", "env", "src"), + }, + Quick: true, + ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) { + assert.NotNil(t, stackInfo.Deployment) + if assert.Equal(t, 9, len(stackInfo.Deployment.Resources)) { + stackRes := stackInfo.Deployment.Resources[0] + assert.NotNil(t, stackRes) + assert.Equal(t, resource.RootStackType, stackRes.Type) + assert.Equal(t, "", string(stackRes.Parent)) + + // Check that dependencies flow correctly between the originating program and the remote component + // plugin. + urns := make(map[string]resource.URN) + for _, res := range stackInfo.Deployment.Resources[1:] { + assert.NotNil(t, res) + + urns[string(res.URN.Name())] = res.URN + switch res.URN.Name() { + case "child-a": + for _, deps := range res.PropertyDependencies { + assert.Empty(t, deps) + } + case "child-b": + assert.Equal(t, []resource.URN{urns["a"]}, res.PropertyDependencies["echo"]) + case "child-c": + assert.ElementsMatch(t, []resource.URN{urns["child-a"], urns["a"]}, + res.PropertyDependencies["echo"]) + } + } + } + }, + } + integration.ProgramTest(t, opts) +} diff --git a/tests/integration/integration_test.go b/tests/integration/integration_test.go index 142b13c51..6f4efeded 100644 --- a/tests/integration/integration_test.go +++ b/tests/integration/integration_test.go @@ -4,7 +4,9 @@ package ints import ( "fmt" + "os" "path/filepath" + "runtime" "strings" "testing" "time" @@ -563,5 +565,21 @@ func TestConfigPaths(t *testing.T) { e.RunCommand("pulumi", "stack", "rm", "--yes") } -// The following 4 tests are testing to ensure that we can make RPC calls >4mb -// Issue: https://github.com/pulumi/pulumi/issues/4155 +//nolint:golint,deadcode +func testComponentPathEnv() (string, error) { + cwd, err := os.Getwd() + if err != nil { + return "", err + } + absCwd, err := filepath.Abs(cwd) + if err != nil { + return "", err + } + pluginDir := filepath.Join(absCwd, "construct_component", "testcomponent") + + pathSeparator := ":" + if runtime.GOOS == "windows" { + pathSeparator = ";" + } + return "PATH=" + os.Getenv("PATH") + pathSeparator + pluginDir, nil +}