diff --git a/changelog/pending/20230120--sdk-go--delegate-alias-computation-to-the-engine.yaml b/changelog/pending/20230120--sdk-go--delegate-alias-computation-to-the-engine.yaml deleted file mode 100644 index 598029346abe..000000000000 --- a/changelog/pending/20230120--sdk-go--delegate-alias-computation-to-the-engine.yaml +++ /dev/null @@ -1,4 +0,0 @@ -changes: -- type: fix - scope: sdk/go - description: Delegate alias computation to the engine diff --git a/sdk/go/pulumi/alias.go b/sdk/go/pulumi/alias.go index 97f53c3b232e..cf9de7aebbad 100644 --- a/sdk/go/pulumi/alias.go +++ b/sdk/go/pulumi/alias.go @@ -134,3 +134,17 @@ func CreateURN(name, t, parent, project, stack StringInput) URNOutput { return createURN(a[0].(string), a[1].(string), a[2].(string), a[3].(string), a[4].(string)) }).(URNOutput) } + +// inheritedChildAlias computes the alias that should be applied to a child based on an alias applied to it's parent. +// This may involve changing the name of the resource in cases where the resource has a named derived from the name of +// the parent, and the parent name changed. +func inheritedChildAlias(childName, parentName, childType, project, stack string, parentURN URNOutput) URNOutput { + aliasName := StringInput(String(childName)) + if strings.HasPrefix(childName, parentName) { + aliasName = parentURN.ApplyT(func(urn URN) string { + parentPrefix := urn[strings.LastIndex(string(urn), "::")+2:] + return string(parentPrefix) + childName[len(parentName):] + }).(StringOutput) + } + return CreateURN(aliasName, String(childType), parentURN.ToStringOutput(), String(project), String(stack)) +} diff --git a/sdk/go/pulumi/context.go b/sdk/go/pulumi/context.go index 24e73e773529..db27857a5464 100644 --- a/sdk/go/pulumi/context.go +++ b/sdk/go/pulumi/context.go @@ -52,14 +52,14 @@ type Context struct { engine pulumirpc.EngineClient engineConn *grpc.ClientConn - keepResources bool // true if resources should be marshaled as strongly-typed references. - keepOutputValues bool // true if outputs should be marshaled as strongly-type output values. - supportsDeletedWith bool // true if deletedWith supported by pulumi - supportsAliasSpec bool // true if full alias specification is supported by pulumi - rpcs int // the number of outstanding RPC requests. - rpcsDone *sync.Cond // an event signaling completion of RPCs. - rpcsLock sync.Mutex // a lock protecting the RPC count and event. - rpcError error // the first error (if any) encountered during an RPC. + keepResources bool // true if resources should be marshaled as strongly-typed references. + keepOutputValues bool // true if outputs should be marshaled as strongly-type output values. + supportsDeletedWith bool // true if deletedWith supported by pulumi + + rpcs int // the number of outstanding RPC requests. + rpcsDone *sync.Cond // an event signaling completion of RPCs. + rpcsLock sync.Mutex // a lock protecting the RPC count and event. + rpcError error // the first error (if any) encountered during an RPC. join workGroup // the waitgroup for non-RPC async work associated with this context @@ -106,9 +106,6 @@ func NewContext(ctx context.Context, info RunInfo) (*Context, error) { monitor = &mockMonitor{project: info.Project, stack: info.Stack, mocks: info.Mocks} engine = &mockEngine{} } - if wrap := info.wrapResourceMonitorClient; wrap != nil { - monitor = wrap(monitor) - } supportsFeature := func(id string) (bool, error) { if monitor != nil { @@ -136,9 +133,8 @@ func NewContext(ctx context.Context, info RunInfo) (*Context, error) { return nil, err } - supportsAliasSpec, err := supportsFeature("aliasSpecs") - if err != nil { - return nil, err + if wrap := info.wrapResourceMonitorClient; wrap != nil { + monitor = wrap(monitor) } context := &Context{ @@ -152,7 +148,6 @@ func NewContext(ctx context.Context, info RunInfo) (*Context, error) { keepResources: keepResources, keepOutputValues: keepOutputValues, supportsDeletedWith: supportsDeletedWith, - supportsAliasSpec: supportsAliasSpec, } context.rpcsDone = sync.NewCond(&context.rpcsLock) context.Log = &logState{ @@ -601,6 +596,7 @@ func (ctx *Context) ReadResource( } options := merge(opts...) + aliasParent := options.Parent if options.Parent == nil { options.Parent = ctx.stack } @@ -612,6 +608,12 @@ func (ctx *Context) ReadResource( return err } + // Collapse aliases to URNs. + aliasURNs, err := ctx.collapseAliases(options.Aliases, t, name, aliasParent) + if err != nil { + return err + } + if options.DeletedWith != nil && !ctx.supportsDeletedWith { return errors.New("the Pulumi CLI does not support the DeletedWith option. Please update the Pulumi CLI") } @@ -632,7 +634,7 @@ func (ctx *Context) ReadResource( // Create resolvers for the resource's outputs. res := ctx.makeResourceState(t, name, resource, providers, provider, - options.Version, options.PluginDownloadURL, transformations) + options.Version, options.PluginDownloadURL, aliasURNs, transformations) // Kick off the resource read operation. This will happen asynchronously and resolve the above properties. go func() { @@ -787,6 +789,7 @@ func (ctx *Context) registerResource( } options := merge(opts...) + parent := options.Parent if options.Parent == nil { options.Parent = ctx.stack } @@ -798,6 +801,12 @@ func (ctx *Context) registerResource( return err } + // Collapse aliases to URNs. + aliasURNs, err := ctx.collapseAliases(options.Aliases, t, name, parent) + if err != nil { + return err + } + // Note that we're about to make an outstanding RPC request, so that we can rendezvous during shutdown. if err := ctx.beginRPC(); err != nil { return err @@ -814,7 +823,7 @@ func (ctx *Context) registerResource( // Create resolvers for the resource's outputs. resState := ctx.makeResourceState(t, name, resource, providers, provider, - options.Version, options.PluginDownloadURL, transformations) + options.Version, options.PluginDownloadURL, aliasURNs, transformations) // Kick off the resource registration. If we are actually performing a deployment, the resulting properties // will be resolved asynchronously as the RPC operation completes. If we're just planning, values won't resolve. @@ -836,14 +845,6 @@ func (ctx *Context) registerResource( return } - var aliasURNs []string - if !ctx.supportsAliasSpec { - aliasURNs = make([]string, len(inputs.aliases)) - for i, alias := range inputs.aliases { - aliasURNs[i] = alias.GetUrn() - } - } - var resp *pulumirpc.RegisterResourceResponse if len(options.URN) > 0 { resp, err = ctx.getResource(options.URN) @@ -869,8 +870,7 @@ func (ctx *Context) registerResource( ImportId: inputs.importID, CustomTimeouts: inputs.customTimeouts, IgnoreChanges: inputs.ignoreChanges, - AliasURNs: aliasURNs, - Aliases: inputs.aliases, + AliasURNs: inputs.aliasURNs, AcceptSecrets: true, AcceptResources: !disableResourceReferences, AdditionalSecretOutputs: inputs.additionalSecretOutputs, @@ -924,6 +924,7 @@ type resourceState struct { provider ProviderResource version string pluginDownloadURL string + aliases []URNOutput name string transformations []ResourceTransformation } @@ -1015,163 +1016,47 @@ func getPackage(t string) string { return components[0] } -func (ctx *Context) resolveAliasParent(alias Alias, spec *pulumirpc.Alias_Spec) error { - var parentURN URNOutput - if alias.ParentURN != nil { - parentURN = alias.ParentURN.ToURNOutput() - } else if alias.Parent != nil { - parentURN = alias.Parent.URN() - } else { - // alias has no original parent - spec.Parent = &pulumirpc.Alias_Spec_NoParent{ - NoParent: true, - } - // We're done here. - return nil - } - - resolvedParentURN, known, secret, err := parentURN.awaitURN(ctx.Context()) - if err != nil { - return fmt.Errorf("alias parent could not be resolved: %w", err) - } - - if !known { - return errors.New("alias parent urn must be known") - } - - if secret { - return errors.New("alias parent urn must not be secret") - } - - spec.Parent = &pulumirpc.Alias_Spec_ParentUrn{ - ParentUrn: string(resolvedParentURN), - } +// collapseAliases collapses a list of Aliases into a list of URNs. Parent aliases +// are also included. If there are N child aliases, and M parent aliases, there will +// be (M+1)*(N+1)-1 total aliases, or, as calculated in the logic below, N+(M*(1+N)). +func (ctx *Context) collapseAliases(aliases []Alias, t, name string, parent Resource) ([]URNOutput, error) { + project, stack := ctx.Project(), ctx.Stack() - return nil -} + aliasURNs := make([]URNOutput, 0, len(aliases)) -// mapAliases maps a list of aliases coming from resource options -// to their RPC representation which the engine understands. -func (ctx *Context) mapAliases(aliases []Alias, - resourceType string, - name string, - parent Resource) ([]*pulumirpc.Alias, error) { - - aliasSpecs := make([]*pulumirpc.Alias, 0, len(aliases)) - await := func(input StringInput) (string, error) { - if input == nil { - return "", nil - } - content, known, secret, _, err := input.ToStringOutput().await(ctx.Context()) + for _, alias := range aliases { + urn, err := alias.collapseToURN(name, t, parent, project, stack) if err != nil { - return "", err - } - - if !known { - return "", errors.New("must be known") - } - - if secret { - return "", errors.New("must not be secret") + return nil, fmt.Errorf("error collapsing alias to URN: %w", err) } - - if content == nil { - // it is fine if the value is nil, we just return an empty string - // the engine can fill this in - return "", nil - } - - value, ok := content.(string) - if !ok { - return "", errors.New("must be a string") - } - return value, nil + aliasURNs = append(aliasURNs, urn) } - if ctx.supportsAliasSpec { - for _, alias := range aliases { - if alias.URN != nil { - // fully specified URN, map it as is - aliasUrn, _, _, err := alias.URN.ToURNOutput().awaitURN(ctx.Context()) + if parent != nil { + parentAliases := parent.getAliases() + for i := range parentAliases { + parentAlias := parentAliases[i] + urn := inheritedChildAlias(name, parent.getName(), t, project, stack, parentAlias) + aliasURNs = append(aliasURNs, urn) + for j := range aliases { + childAlias := aliases[j] + urn, err := childAlias.collapseToURN(name, t, parent, project, stack) if err != nil { - return nil, fmt.Errorf("alias urn could not be resolved: %w", err) + return nil, fmt.Errorf("error collapsing alias to URN: %w", err) } - newAliasSpec := &pulumirpc.Alias{ - Alias: &pulumirpc.Alias_Urn{ - Urn: string(aliasUrn), - }, - } - - aliasSpecs = append(aliasSpecs, newAliasSpec) - continue - } - - aliasName, err := await(alias.Name) - if err != nil { - return nil, fmt.Errorf("alias name could not be resolved: %w", err) - } - - aliasType, err := await(alias.Type) - if err != nil { - return nil, fmt.Errorf("alias type could not be resolved: %w", err) - } - - aliasProject, err := await(alias.Project) - if err != nil { - return nil, fmt.Errorf("alias project could not be resolved: %w", err) - } - - aliasStack, err := await(alias.Stack) - if err != nil { - return nil, fmt.Errorf("alias stack could not be resolved: %w", err) + inheritedAlias := urn.ApplyT(func(urn URN) URNOutput { + aliasedChildName := string(resource.URN(urn).Name()) + aliasedChildType := string(resource.URN(urn).Type()) + return inheritedChildAlias(aliasedChildName, parent.getName(), aliasedChildType, project, stack, parentAlias) + }).ApplyT(func(urn interface{}) URN { + return urn.(URN) + }).(URNOutput) + aliasURNs = append(aliasURNs, inheritedAlias) } - - spec := &pulumirpc.Alias_Spec{ - Name: aliasName, - Type: aliasType, - Project: aliasProject, - Stack: aliasStack, - } - - if err := ctx.resolveAliasParent(alias, spec); err != nil { - return nil, fmt.Errorf("alias parent could not be resolved: %w", err) - } - - newAliasSpec := &pulumirpc.Alias{ - Alias: &pulumirpc.Alias_Spec_{ - Spec: spec, - }, - } - - aliasSpecs = append(aliasSpecs, newAliasSpec) - } - } else { - // If the engine does not support full alias specs, we will use the URN format - // Collapse top level aliases into urns - // this populates the aliasURNs of the resourceInputs - // which is then used in RegisterResourceRequest - for _, alias := range aliases { - urnToAwait, err := alias.collapseToURN(name, resourceType, parent, ctx.Project(), ctx.Stack()) - if err != nil { - return nil, fmt.Errorf("error collapsing alias to URN: %w", err) - } - - urn, _, _, err := urnToAwait.awaitURN(ctx.Context()) - if err != nil { - return nil, fmt.Errorf("error waiting for alias URN to resolve: %w", err) - } - - newAliasSpec := &pulumirpc.Alias{ - Alias: &pulumirpc.Alias_Urn{ - Urn: string(urn), - }, - } - - aliasSpecs = append(aliasSpecs, newAliasSpec) } } - return aliasSpecs, nil + return aliasURNs, nil } var mapOutputType = reflect.TypeOf((*MapOutput)(nil)).Elem() @@ -1179,7 +1064,7 @@ var mapOutputType = reflect.TypeOf((*MapOutput)(nil)).Elem() // makeResourceState creates a set of resolvers that we'll use to finalize state, for URNs, IDs, and output // properties. func (ctx *Context) makeResourceState(t, name string, resourceV Resource, providers map[string]ProviderResource, - provider ProviderResource, version, pluginDownloadURL string, + provider ProviderResource, version, pluginDownloadURL string, aliases []URNOutput, transformations []ResourceTransformation) *resourceState { // Ensure that the input res is a pointer to a struct. Note that we don't fail if it is not, and we probably @@ -1277,6 +1162,8 @@ func (ctx *Context) makeResourceState(t, name string, resourceV Resource, provid state.outputs["urn"] = rs.urn state.name = name rs.name = name + state.aliases = aliases + rs.aliases = aliases state.transformations = transformations rs.transformations = transformations } @@ -1380,7 +1267,7 @@ type resourceInputs struct { importID string customTimeouts *pulumirpc.RegisterResourceRequest_CustomTimeouts ignoreChanges []string - aliases []*pulumirpc.Alias + aliasURNs []string additionalSecretOutputs []string version string pluginDownloadURL string @@ -1445,9 +1332,14 @@ func (ctx *Context) prepareResourceInputs(res Resource, props Input, t string, o } sort.Strings(deps) - aliases, err := ctx.mapAliases(opts.Aliases, t, state.name, opts.Parent) - if err != nil { - return nil, fmt.Errorf("mapping aliases: %w", err) + // Await alias URNs + aliases := make([]string, len(state.aliases)) + for i, alias := range state.aliases { + urn, _, _, err := alias.awaitURN(context.Background()) + if err != nil { + return nil, fmt.Errorf("error waiting for alias URN to resolve: %w", err) + } + aliases[i] = string(urn) } var deletedWithURN URN @@ -1472,7 +1364,7 @@ func (ctx *Context) prepareResourceInputs(res Resource, props Input, t string, o importID: string(resOpts.importID), customTimeouts: getTimeouts(opts.CustomTimeouts), ignoreChanges: resOpts.ignoreChanges, - aliases: aliases, + aliasURNs: aliases, additionalSecretOutputs: resOpts.additionalSecretOutputs, version: state.version, pluginDownloadURL: state.pluginDownloadURL, diff --git a/sdk/go/pulumi/context_test.go b/sdk/go/pulumi/context_test.go index 172f3300f203..c0b0cae8e259 100644 --- a/sdk/go/pulumi/context_test.go +++ b/sdk/go/pulumi/context_test.go @@ -15,17 +15,14 @@ package pulumi import ( - "context" "fmt" "strings" "testing" "time" - "github.com/pulumi/pulumi/sdk/v3/go/common/resource" - pulumirpc "github.com/pulumi/pulumi/sdk/v3/proto/go" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "google.golang.org/grpc" + + "github.com/pulumi/pulumi/sdk/v3/go/common/resource" ) // The test is extracted from a panic using pulumi-docker and minified @@ -152,6 +149,105 @@ func TestWaitingCausesNoPanics(t *testing.T) { } } +func TestCollapseAliases(t *testing.T) { + t.Parallel() + + mocks := &testMonitor{ + NewResourceF: func(args MockResourceArgs) (string, resource.PropertyMap, error) { + assert.Equal(t, "test:resource:type", args.TypeToken) + return "myID", resource.PropertyMap{"foo": resource.NewStringProperty("qux")}, nil + }, + } + + testCases := []struct { + parentAliases []Alias + childAliases []Alias + totalAliasUrns int + results []URN + }{ + { + parentAliases: []Alias{}, + childAliases: []Alias{}, + totalAliasUrns: 0, + results: []URN{}, + }, + { + parentAliases: []Alias{}, + childAliases: []Alias{{Type: String("test:resource:child2")}}, + totalAliasUrns: 1, + results: []URN{"urn:pulumi:stack::project::test:resource:type$test:resource:child2::myres-child"}, + }, + { + parentAliases: []Alias{}, + childAliases: []Alias{{Name: String("child2")}}, + totalAliasUrns: 1, + results: []URN{"urn:pulumi:stack::project::test:resource:type$test:resource:child::child2"}, + }, + { + parentAliases: []Alias{{Type: String("test:resource:type3")}}, + childAliases: []Alias{{Name: String("myres-child2")}}, + totalAliasUrns: 3, + results: []URN{ + "urn:pulumi:stack::project::test:resource:type$test:resource:child::myres-child2", + "urn:pulumi:stack::project::test:resource:type3$test:resource:child::myres-child", + "urn:pulumi:stack::project::test:resource:type3$test:resource:child::myres-child2", + }, + }, + { + parentAliases: []Alias{{Name: String("myres2")}}, + childAliases: []Alias{{Name: String("myres-child2")}}, + totalAliasUrns: 3, + results: []URN{ + "urn:pulumi:stack::project::test:resource:type$test:resource:child::myres-child2", + "urn:pulumi:stack::project::test:resource:type$test:resource:child::myres2-child", + "urn:pulumi:stack::project::test:resource:type$test:resource:child::myres2-child2", + }, + }, + { + parentAliases: []Alias{{Name: String("myres2")}, {Type: String("test:resource:type3")}, {Name: String("myres3")}}, + childAliases: []Alias{{Name: String("myres-child2")}, {Type: String("test:resource:child2")}}, + totalAliasUrns: 11, + results: []URN{ + "urn:pulumi:stack::project::test:resource:type$test:resource:child::myres-child2", + "urn:pulumi:stack::project::test:resource:type$test:resource:child2::myres-child", + "urn:pulumi:stack::project::test:resource:type$test:resource:child::myres2-child", + "urn:pulumi:stack::project::test:resource:type$test:resource:child::myres2-child2", + "urn:pulumi:stack::project::test:resource:type$test:resource:child2::myres2-child", + "urn:pulumi:stack::project::test:resource:type3$test:resource:child::myres-child", + "urn:pulumi:stack::project::test:resource:type3$test:resource:child::myres-child2", + "urn:pulumi:stack::project::test:resource:type3$test:resource:child2::myres-child", + "urn:pulumi:stack::project::test:resource:type$test:resource:child::myres3-child", + "urn:pulumi:stack::project::test:resource:type$test:resource:child::myres3-child2", + "urn:pulumi:stack::project::test:resource:type$test:resource:child2::myres3-child", + }, + }, + } + + for i := range testCases { + testCase := testCases[i] + err := RunErr(func(ctx *Context) error { + var res testResource2 + err := ctx.RegisterResource("test:resource:type", "myres", &testResource2Inputs{}, &res, + Aliases(testCase.parentAliases)) + assert.NoError(t, err) + urns, err := ctx.collapseAliases(testCase.childAliases, "test:resource:child", "myres-child", &res) + assert.NoError(t, err) + assert.Len(t, urns, testCase.totalAliasUrns) + var items []interface{} + for _, item := range urns { + items = append(items, item) + } + All(items...).ApplyT(func(urns interface{}) bool { + assert.ElementsMatch(t, urns, testCase.results) + return true + }) + return nil + }, WithMocks("project", "stack", mocks)) + assert.NoError(t, err) + } + +} + // Context with which to create a ProviderResource. type Prov struct { name string @@ -277,203 +373,3 @@ func TestMergeProviders(t *testing.T) { }) } } - -func TestRegisterResource_aliasesSpecs(t *testing.T) { - t.Parallel() - - parentURN := CreateURN( - String("parent"), - String("test:resource:parentType"), - String(""), - String("project"), - String("stack"), - ) - - tests := []struct { - desc string - give []Alias - - // Whether the monitor supports aliasSpecs. - supportsAliasSpecs bool - - // Specifies what we expect on the RegisterResourceRequest. - // Typically, if a server supports AliasSpecs, - // we won't send AliasURNs. - wantAliases []*pulumirpc.Alias - wantAliasURNs []string - }{ - { - desc: "no parent/before alias specs", - give: []Alias{ - {Name: String("resA"), NoParent: Bool(true)}, - {Name: String("resB"), NoParent: Bool(true)}, - }, - wantAliases: []*pulumirpc.Alias{ - { - Alias: &pulumirpc.Alias_Urn{ - Urn: "urn:pulumi:stack::project::test:resource:type::resA", - }, - }, - { - Alias: &pulumirpc.Alias_Urn{ - Urn: "urn:pulumi:stack::project::test:resource:type::resB", - }, - }, - }, - wantAliasURNs: []string{ - "urn:pulumi:stack::project::test:resource:type::resA", - "urn:pulumi:stack::project::test:resource:type::resB", - }, - }, - { - desc: "no parent/with alias specs", - supportsAliasSpecs: true, - give: []Alias{ - {Name: String("resA"), NoParent: Bool(true)}, - {Name: String("resB"), NoParent: Bool(true)}, - }, - wantAliases: []*pulumirpc.Alias{ - { - Alias: &pulumirpc.Alias_Spec_{ - Spec: &pulumirpc.Alias_Spec{ - Name: "resA", - Parent: &pulumirpc.Alias_Spec_NoParent{NoParent: true}, - }, - }, - }, - { - Alias: &pulumirpc.Alias_Spec_{ - Spec: &pulumirpc.Alias_Spec{ - Name: "resB", - Parent: &pulumirpc.Alias_Spec_NoParent{NoParent: true}, - }, - }, - }, - }, - }, - { - desc: "parent urn/no alias specs", - give: []Alias{ - {Name: String("child"), ParentURN: parentURN}, - }, - wantAliasURNs: []string{ - "urn:pulumi:stack::project::test:resource:parentType$test:resource:type::child", - }, - wantAliases: []*pulumirpc.Alias{ - { - Alias: &pulumirpc.Alias_Urn{ - Urn: "urn:pulumi:stack::project::test:resource:parentType$test:resource:type::child", - }, - }, - }, - }, - { - desc: "parent urn/alias specs", - give: []Alias{ - {Name: String("child"), ParentURN: parentURN}, - }, - supportsAliasSpecs: true, - wantAliases: []*pulumirpc.Alias{ - { - Alias: &pulumirpc.Alias_Spec_{ - Spec: &pulumirpc.Alias_Spec{ - Name: "child", - Parent: &pulumirpc.Alias_Spec_ParentUrn{ - ParentUrn: "urn:pulumi:stack::project::test:resource:parentType::parent", - }, - }, - }, - }, - }, - }, - } - - for _, tt := range tests { - tt := tt - t.Run(tt.desc, func(t *testing.T) { - t.Parallel() - - var ( - gotAliases []*pulumirpc.Alias - gotAliasURNS []string - ) - monitor := &testMonitor{ - NewResourceF: func(args MockResourceArgs) (string, resource.PropertyMap, error) { - gotAliases = append(gotAliases, args.RegisterRPC.Aliases...) - gotAliasURNS = append(gotAliasURNS, args.RegisterRPC.AliasURNs...) - return args.Name, resource.PropertyMap{}, nil - }, - } - - opts := []RunOption{ - WithMocks("project", "stack", monitor), - } - - // The mock resource monitor client does not support - // alias specs. - // So if that's needed, wrap the monitor to claim it - // does. - if tt.supportsAliasSpecs { - opts = append(opts, WrapResourceMonitorClient( - func(rmc pulumirpc.ResourceMonitorClient) pulumirpc.ResourceMonitorClient { - return resourceMonitorClientWithFeatures(rmc, "aliasSpecs") - })) - } - - err := RunErr(func(ctx *Context) error { - var res testResource2 - err := ctx.RegisterResource( - "test:resource:type", - "resNew", - &testResource2Inputs{Foo: String("oof")}, - &res, - Aliases(tt.give), - ) - require.NoError(t, err) - return nil - }, opts...) - require.NoError(t, err) - - assert.Equal(t, tt.wantAliases, gotAliases, "Aliases did not match") - assert.Equal(t, tt.wantAliasURNs, gotAliasURNS, "AliasURNs did not match") - }) - } -} - -// resmonClientWithFeatures wraps a ResourceMonitorClient -// to report various additional features as supported. -type resmonClientWithFeatures struct { - pulumirpc.ResourceMonitorClient - - features map[string]struct{} -} - -// resourceMonitorClientWithFeatures builds a ResourceMonitorClient -// that reports the provided feature names as supported -// in addition to those already supported by the client. -func resourceMonitorClientWithFeatures( - cl pulumirpc.ResourceMonitorClient, - features ...string, -) pulumirpc.ResourceMonitorClient { - featureSet := make(map[string]struct{}, len(features)) - for _, f := range features { - featureSet[f] = struct{}{} - } - return &resmonClientWithFeatures{ - ResourceMonitorClient: cl, - features: featureSet, - } -} - -func (c *resmonClientWithFeatures) SupportsFeature( - ctx context.Context, - req *pulumirpc.SupportsFeatureRequest, - opts ...grpc.CallOption, -) (*pulumirpc.SupportsFeatureResponse, error) { - if _, ok := c.features[req.GetId()]; ok { - return &pulumirpc.SupportsFeatureResponse{ - HasSupport: ok, - }, nil - } - return c.ResourceMonitorClient.SupportsFeature(ctx, req, opts...) -} diff --git a/sdk/go/pulumi/rpc_test.go b/sdk/go/pulumi/rpc_test.go index a4fa476d5e28..448335040544 100644 --- a/sdk/go/pulumi/rpc_test.go +++ b/sdk/go/pulumi/rpc_test.go @@ -420,7 +420,7 @@ func TestResourceState(t *testing.T) { assert.Nil(t, err) var theResource testResource - state := ctx.makeResourceState("", "", &theResource, nil, nil, "", "", nil) + state := ctx.makeResourceState("", "", &theResource, nil, nil, "", "", nil, nil) resolved, _, _, _ := marshalInputs(&testResourceInputs{ Any: String("foo"), @@ -875,7 +875,7 @@ func TestDependsOnComponent(t *testing.T) { registerResource := func(name string, res Resource, custom bool, options ...ResourceOption) (Resource, []string) { opts := merge(options...) - state := ctx.makeResourceState("", "", res, nil, nil, "", "", nil) + state := ctx.makeResourceState("", "", res, nil, nil, "", "", nil, nil) state.resolve(ctx, nil, nil, name, "", &structpb.Struct{}, nil) inputs, err := ctx.prepareResourceInputs(res, Map{}, "", opts, state, false, custom)