From 49d363c00f26e97d6d9e764ab3ba5ea548078386 Mon Sep 17 00:00:00 2001 From: Rain Date: Tue, 11 Feb 2025 01:27:24 -0500 Subject: [PATCH 01/25] Started implementing resource identity for tf5muxserver --- go.mod | 10 +- go.sum | 40 +- internal/tf5testserver/tf5testserver.go | 28 ++ tf5muxserver/mux_server.go | 5 + .../mux_server_GetResourceIdentitySchemas.go | 59 +++ ..._server_GetResourceIdentitySchemas_test.go | 370 ++++++++++++++++++ .../mux_server_UpgradeResourceIdentity.go | 54 +++ ...mux_server_UpgradeResourceIdentity_test.go | 79 ++++ 8 files changed, 620 insertions(+), 25 deletions(-) create mode 100644 tf5muxserver/mux_server_GetResourceIdentitySchemas.go create mode 100644 tf5muxserver/mux_server_GetResourceIdentitySchemas_test.go create mode 100644 tf5muxserver/mux_server_UpgradeResourceIdentity.go create mode 100644 tf5muxserver/mux_server_UpgradeResourceIdentity_test.go diff --git a/go.mod b/go.mod index add70f1..c368bf5 100644 --- a/go.mod +++ b/go.mod @@ -6,16 +6,16 @@ toolchain go1.22.7 require ( github.com/google/go-cmp v0.6.0 - github.com/hashicorp/terraform-plugin-go v0.26.0 + github.com/hashicorp/terraform-plugin-go v0.26.1-0.20250210164912-1d335b3d83c3 github.com/hashicorp/terraform-plugin-log v0.9.0 - google.golang.org/grpc v1.69.4 + google.golang.org/grpc v1.70.0 ) require ( github.com/fatih/color v1.13.0 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/hashicorp/go-hclog v1.5.0 // indirect - github.com/hashicorp/go-plugin v1.6.2 // indirect + github.com/hashicorp/go-plugin v1.6.3 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/hashicorp/terraform-registry-address v0.2.4 // indirect github.com/hashicorp/terraform-svchost v0.1.1 // indirect @@ -29,6 +29,6 @@ require ( golang.org/x/net v0.34.0 // indirect golang.org/x/sys v0.29.0 // indirect golang.org/x/text v0.21.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 // indirect - google.golang.org/protobuf v1.36.3 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a // indirect + google.golang.org/protobuf v1.36.4 // indirect ) diff --git a/go.sum b/go.sum index 5a58652..7b16699 100644 --- a/go.sum +++ b/go.sum @@ -17,12 +17,12 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= -github.com/hashicorp/go-plugin v1.6.2 h1:zdGAEd0V1lCaU0u+MxWQhtSDQmahpkwOun8U8EiRVog= -github.com/hashicorp/go-plugin v1.6.2/go.mod h1:CkgLQ5CZqNmdL9U9JzM532t8ZiYQ35+pj3b1FD37R0Q= +github.com/hashicorp/go-plugin v1.6.3 h1:xgHB+ZUSYeuJi96WtxEjzi23uh7YQpznjGh0U0UUrwg= +github.com/hashicorp/go-plugin v1.6.3/go.mod h1:MRobyh+Wc/nYy1V4KAXUiYfzxoYhs7V1mlH1Z7iY2h0= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/terraform-plugin-go v0.26.0 h1:cuIzCv4qwigug3OS7iKhpGAbZTiypAfFQmw8aE65O2M= -github.com/hashicorp/terraform-plugin-go v0.26.0/go.mod h1:+CXjuLDiFgqR+GcrM5a2E2Kal5t5q2jb0E3D57tTdNY= +github.com/hashicorp/terraform-plugin-go v0.26.1-0.20250210164912-1d335b3d83c3 h1:1mWCKXiCv8KChHk9mHJjJvhWHBQ+MFkHfowvVkiiQk0= +github.com/hashicorp/terraform-plugin-go v0.26.1-0.20250210164912-1d335b3d83c3/go.mod h1:6Ivn6mt9Ov7gMiYNNCRsQm4N0Kaq28gv3z/Q64qcBwI= github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0= github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow= github.com/hashicorp/terraform-registry-address v0.2.4 h1:JXu/zHB2Ymg/TGVCRu10XqNa4Sh2bWcqCNyKWjnCPJA= @@ -54,16 +54,16 @@ github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IU github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= -go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY= -go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE= -go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE= -go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY= -go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk= -go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0= -go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc= -go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8= -go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys= -go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A= +go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= +go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= +go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= +go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= +go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= +go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= +go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiyYCU9snn1CU= +go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ= +go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= +go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -76,12 +76,12 @@ golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 h1:X58yt85/IXCx0Y3ZwN6sEIKZzQtDEYaBWrDvErdXrRE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= -google.golang.org/grpc v1.69.4 h1:MF5TftSMkd8GLw/m0KM6V8CMOCY6NZ1NQDPGFgbTt4A= -google.golang.org/grpc v1.69.4/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= -google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU= -google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a h1:hgh8P4EuoxpsuKMXX/To36nOFD7vixReXgn8lPGnt+o= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= +google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= +google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= +google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM= +google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/tf5testserver/tf5testserver.go b/internal/tf5testserver/tf5testserver.go index 83b11de..12a6dee 100644 --- a/internal/tf5testserver/tf5testserver.go +++ b/internal/tf5testserver/tf5testserver.go @@ -32,6 +32,9 @@ type TestServer struct { GetProviderSchemaCalled bool GetProviderSchemaResponse *tfprotov5.GetProviderSchemaResponse + GetResourceIdentitySchemaCalled bool + GetResourceIdentityResponse *tfprotov5.GetResourceIdentitySchemasResponse + ImportResourceStateCalled map[string]bool MoveResourceStateCalled map[string]bool @@ -52,6 +55,8 @@ type TestServer struct { StopProviderCalled bool StopProviderResponse *tfprotov5.StopProviderResponse + UpgradeResourceIdentityCalled map[string]bool + UpgradeResourceStateCalled map[string]bool ValidateEphemeralResourceConfigCalled map[string]bool @@ -136,6 +141,16 @@ func (s *TestServer) GetProviderSchema(_ context.Context, _ *tfprotov5.GetProvid return &tfprotov5.GetProviderSchemaResponse{}, nil } +func (s *TestServer) GetResourceIdentitySchemas(_ context.Context, _ *tfprotov5.GetResourceIdentitySchemasRequest) (*tfprotov5.GetResourceIdentitySchemasResponse, error) { + s.GetResourceIdentitySchemaCalled = true + + if s.GetResourceIdentityResponse != nil { + return s.GetResourceIdentityResponse, nil + } + + return &tfprotov5.GetResourceIdentitySchemasResponse{}, nil +} + func (s *TestServer) ImportResourceState(_ context.Context, req *tfprotov5.ImportResourceStateRequest) (*tfprotov5.ImportResourceStateResponse, error) { if s.ImportResourceStateCalled == nil { s.ImportResourceStateCalled = make(map[string]bool) @@ -209,6 +224,15 @@ func (s *TestServer) StopProvider(_ context.Context, _ *tfprotov5.StopProviderRe return &tfprotov5.StopProviderResponse{}, nil } +func (s *TestServer) UpgradeResourceIdentity(_ context.Context, req *tfprotov5.UpgradeResourceIdentityRequest) (*tfprotov5.UpgradeResourceIdentityResponse, error) { + if s.UpgradeResourceIdentityCalled == nil { + s.UpgradeResourceIdentityCalled = make(map[string]bool) + } + + s.UpgradeResourceIdentityCalled[req.TypeName] = true + return nil, nil +} + func (s *TestServer) UpgradeResourceState(_ context.Context, req *tfprotov5.UpgradeResourceStateRequest) (*tfprotov5.UpgradeResourceStateResponse, error) { if s.UpgradeResourceStateCalled == nil { s.UpgradeResourceStateCalled = make(map[string]bool) @@ -249,3 +273,7 @@ func (s *TestServer) PrepareProviderConfig(_ context.Context, req *tfprotov5.Pre s.PrepareProviderConfigCalled = true return s.PrepareProviderConfigResponse, nil } + +func (s *TestServer) ProviderServerWithResourceIdentity() tfprotov5.ProviderServerWithResourceIdentity { + return s +} diff --git a/tf5muxserver/mux_server.go b/tf5muxserver/mux_server.go index ba23971..f376f10 100644 --- a/tf5muxserver/mux_server.go +++ b/tf5muxserver/mux_server.go @@ -35,6 +35,9 @@ type muxServer struct { // Resource capabilities are cached during GetMetadata/GetProviderSchema resourceCapabilities map[string]*tfprotov5.ServerCapabilities + // Routing for resource identity + resourceIdentity map[string]tfprotov5.ProviderServer + // serverDiscoveryComplete is whether the mux server's underlying server // discovery of resource types has been completed against all servers. // If false during a resource type specific RPC, the mux server needs to @@ -349,11 +352,13 @@ func (s *muxServer) serverDiscovery(ctx context.Context) error { // - Only one provider implements each data source // - Only one provider implements each function // - Only one provider implements each ephemeral resource +// - Only one provider implements each resource identity func NewMuxServer(_ context.Context, servers ...func() tfprotov5.ProviderServer) (*muxServer, error) { result := muxServer{ dataSources: make(map[string]tfprotov5.ProviderServer), ephemeralResources: make(map[string]tfprotov5.ProviderServer), functions: make(map[string]tfprotov5.ProviderServer), + resourceIdentity: make(map[string]tfprotov5.ProviderServer), resources: make(map[string]tfprotov5.ProviderServer), resourceCapabilities: make(map[string]*tfprotov5.ServerCapabilities), } diff --git a/tf5muxserver/mux_server_GetResourceIdentitySchemas.go b/tf5muxserver/mux_server_GetResourceIdentitySchemas.go new file mode 100644 index 0000000..7775b32 --- /dev/null +++ b/tf5muxserver/mux_server_GetResourceIdentitySchemas.go @@ -0,0 +1,59 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package tf5muxserver + +import ( + "context" + "fmt" + "github.com/hashicorp/terraform-plugin-go/tfprotov5" + + "github.com/hashicorp/terraform-plugin-mux/internal/logging" +) + +// GetResourceIdentitySchemas merges the schemas returned by the +// tfprotov5.ResourceIdentitySchema associated with muxServer into a single schema. +// Everything must be returned from only one server. +// Schemas must be identical between all servers. +func (s *muxServer) GetResourceIdentitySchemas(ctx context.Context, req *tfprotov5.GetResourceIdentitySchemasRequest) (*tfprotov5.GetResourceIdentitySchemasResponse, error) { + rpc := "GetResourceIdentitySchemas" + ctx = logging.InitContext(ctx) + ctx = logging.RpcContext(ctx, rpc) + + s.serverDiscoveryMutex.Lock() + defer s.serverDiscoveryMutex.Unlock() + + resp := &tfprotov5.GetResourceIdentitySchemasResponse{ + IdentitySchemas: map[string]*tfprotov5.ResourceIdentitySchema{}, + Diagnostics: []*tfprotov5.Diagnostic{}, + } + + for _, server := range s.servers { + ctx := logging.Tfprotov5ProviderServerContext(ctx, server) + logging.MuxTrace(ctx, "calling downstream server") + + // TODO: Remove and call server.GetResourceIdentitySchemas below directly once interface becomes required. + resourceIdentityServer, err := server.(tfprotov5.ProviderServerWithResourceIdentity).GetResourceIdentitySchemas(ctx, req) + + if err != nil { + return resp, fmt.Errorf("error calling GetResourceIdentitySchemas for %T: %w", server, err) + } + + resp.Diagnostics = append(resp.Diagnostics, resourceIdentityServer.Diagnostics...) + + for resourceIdentityType, schema := range resourceIdentityServer.IdentitySchemas { + if _, ok := resp.IdentitySchemas[resourceIdentityType]; ok { + resp.Diagnostics = append(resp.Diagnostics, ephemeralResourceDuplicateError(resourceIdentityType)) + + continue + } + + s.resourceIdentity[resourceIdentityType] = server + resp.IdentitySchemas[resourceIdentityType] = schema + } + } + + s.serverDiscoveryComplete = true + + return resp, nil +} diff --git a/tf5muxserver/mux_server_GetResourceIdentitySchemas_test.go b/tf5muxserver/mux_server_GetResourceIdentitySchemas_test.go new file mode 100644 index 0000000..f084781 --- /dev/null +++ b/tf5muxserver/mux_server_GetResourceIdentitySchemas_test.go @@ -0,0 +1,370 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package tf5muxserver_test + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-go/tfprotov5" + + "github.com/hashicorp/terraform-plugin-mux/internal/tf5testserver" + "github.com/hashicorp/terraform-plugin-mux/tf5muxserver" +) + +func TestMuxServerGetResourceIdentitySchema(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + servers []func() tfprotov5.ProviderServer + expectedIdentitySchemas map[string]*tfprotov5.ResourceIdentitySchema + expectedDiagnostics []*tfprotov5.Diagnostic + }{ + "combined": { + servers: []func() tfprotov5.ProviderServer{ + (&tf5testserver.TestServer{ + GetResourceIdentityResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ + Diagnostics: []*tfprotov5.Diagnostic{}, + IdentitySchemas: map[string]*tfprotov5.ResourceIdentitySchema{ + "test_resource_identity_foo": { + Version: 1, + IdentityAttributes: []*tfprotov5.ResourceIdentitySchemaAttribute{ + { + Name: "req", + RequiredForImport: true, + Description: "this one's required", + }, + { + Name: "opt", + OptionalForImport: true, + Description: "this one's optional", + }, + }, + }, + "test_resource_identity_bar": { + Version: 1, + IdentityAttributes: []*tfprotov5.ResourceIdentitySchemaAttribute{ + { + Name: "req", + RequiredForImport: true, + Description: "this one's required", + }, + { + Name: "opt", + OptionalForImport: true, + Description: "this one's optional", + }, + }, + }, + }, + }, + }).ProviderServer, + (&tf5testserver.TestServer{ + GetResourceIdentityResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ + Diagnostics: []*tfprotov5.Diagnostic{}, + IdentitySchemas: map[string]*tfprotov5.ResourceIdentitySchema{ + "test_resource_identity_foobar": { + Version: 1, + IdentityAttributes: []*tfprotov5.ResourceIdentitySchemaAttribute{ + { + Name: "req", + RequiredForImport: true, + Description: "this one's required", + }, + { + Name: "opt", + OptionalForImport: true, + Description: "this one's optional", + }, + }, + }, + }, + }, + }).ProviderServer, + }, + expectedIdentitySchemas: map[string]*tfprotov5.ResourceIdentitySchema{ + "test_resource_identity_foo": { + Version: 1, + IdentityAttributes: []*tfprotov5.ResourceIdentitySchemaAttribute{ + { + Name: "req", + RequiredForImport: true, + Description: "this one's required", + }, + { + Name: "opt", + OptionalForImport: true, + Description: "this one's optional", + }, + }, + }, + "test_resource_identity_bar": { + Version: 1, + IdentityAttributes: []*tfprotov5.ResourceIdentitySchemaAttribute{ + { + Name: "req", + RequiredForImport: true, + Description: "this one's required", + }, + { + Name: "opt", + OptionalForImport: true, + Description: "this one's optional", + }, + }, + }, + "test_resource_identity_foobar": { + Version: 1, + IdentityAttributes: []*tfprotov5.ResourceIdentitySchemaAttribute{ + { + Name: "req", + RequiredForImport: true, + Description: "this one's required", + }, + { + Name: "opt", + OptionalForImport: true, + Description: "this one's optional", + }, + }, + }, + }, + }, + "duplicate-identity-schema-type": { + servers: []func() tfprotov5.ProviderServer{ + (&tf5testserver.TestServer{ + GetResourceIdentityResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ + IdentitySchemas: map[string]*tfprotov5.ResourceIdentitySchema{ + "test_foo": {}, + }, + }, + }).ProviderServer, + (&tf5testserver.TestServer{ + GetResourceIdentityResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ + IdentitySchemas: map[string]*tfprotov5.ResourceIdentitySchema{ + "test_foo": {}, + }, + }, + }).ProviderServer, + }, + expectedIdentitySchemas: map[string]*tfprotov5.ResourceIdentitySchema{ + "test_foo": {}, + }, + expectedDiagnostics: []*tfprotov5.Diagnostic{ + { + Severity: tfprotov5.DiagnosticSeverityError, + Summary: "Invalid Provider Server Combination", + Detail: "The combined provider has multiple implementations of the same data source type across underlying providers. " + + "Data source types must be implemented by only one underlying provider. " + + "This is always an issue in the provider implementation and should be reported to the provider developers.\n\n" + + "Duplicate data source type: test_foo", + }, + }, + }, + "error-once": { + servers: []func() tfprotov5.ProviderServer{ + (&tf5testserver.TestServer{ + GetResourceIdentityResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ + Diagnostics: []*tfprotov5.Diagnostic{ + { + Severity: tfprotov5.DiagnosticSeverityError, + Summary: "test error summary", + Detail: "test error details", + }, + }, + }, + }).ProviderServer, + (&tf5testserver.TestServer{}).ProviderServer, + (&tf5testserver.TestServer{}).ProviderServer, + }, + expectedIdentitySchemas: map[string]*tfprotov5.ResourceIdentitySchema{}, + expectedDiagnostics: []*tfprotov5.Diagnostic{ + { + Severity: tfprotov5.DiagnosticSeverityError, + Summary: "test error summary", + Detail: "test error details", + }, + }, + }, + "error-multiple": { + servers: []func() tfprotov5.ProviderServer{ + (&tf5testserver.TestServer{ + GetResourceIdentityResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ + Diagnostics: []*tfprotov5.Diagnostic{ + { + Severity: tfprotov5.DiagnosticSeverityError, + Summary: "test error summary", + Detail: "test error details", + }, + }, + }, + }).ProviderServer, + (&tf5testserver.TestServer{}).ProviderServer, + (&tf5testserver.TestServer{ + GetResourceIdentityResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ + Diagnostics: []*tfprotov5.Diagnostic{ + { + Severity: tfprotov5.DiagnosticSeverityError, + Summary: "test error summary", + Detail: "test error details", + }, + }, + }, + }).ProviderServer, + }, + expectedIdentitySchemas: map[string]*tfprotov5.ResourceIdentitySchema{}, + expectedDiagnostics: []*tfprotov5.Diagnostic{ + { + Severity: tfprotov5.DiagnosticSeverityError, + Summary: "test error summary", + Detail: "test error details", + }, + { + Severity: tfprotov5.DiagnosticSeverityError, + Summary: "test error summary", + Detail: "test error details", + }, + }, + }, + "warning-once": { + servers: []func() tfprotov5.ProviderServer{ + (&tf5testserver.TestServer{ + GetResourceIdentityResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ + Diagnostics: []*tfprotov5.Diagnostic{ + { + Severity: tfprotov5.DiagnosticSeverityWarning, + Summary: "test warning summary", + Detail: "test warning details", + }, + }, + }, + }).ProviderServer, + (&tf5testserver.TestServer{}).ProviderServer, + (&tf5testserver.TestServer{}).ProviderServer, + }, + expectedIdentitySchemas: map[string]*tfprotov5.ResourceIdentitySchema{}, + expectedDiagnostics: []*tfprotov5.Diagnostic{ + { + Severity: tfprotov5.DiagnosticSeverityWarning, + Summary: "test warning summary", + Detail: "test warning details", + }, + }, + }, + "warning-multiple": { + servers: []func() tfprotov5.ProviderServer{ + (&tf5testserver.TestServer{ + GetResourceIdentityResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ + Diagnostics: []*tfprotov5.Diagnostic{ + { + Severity: tfprotov5.DiagnosticSeverityWarning, + Summary: "test warning summary", + Detail: "test warning details", + }, + }, + }, + }).ProviderServer, + (&tf5testserver.TestServer{}).ProviderServer, + (&tf5testserver.TestServer{ + GetResourceIdentityResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ + Diagnostics: []*tfprotov5.Diagnostic{ + { + Severity: tfprotov5.DiagnosticSeverityWarning, + Summary: "test warning summary", + Detail: "test warning details", + }, + }, + }, + }).ProviderServer, + }, + expectedIdentitySchemas: map[string]*tfprotov5.ResourceIdentitySchema{}, + expectedDiagnostics: []*tfprotov5.Diagnostic{ + { + Severity: tfprotov5.DiagnosticSeverityWarning, + Summary: "test warning summary", + Detail: "test warning details", + }, + { + Severity: tfprotov5.DiagnosticSeverityWarning, + Summary: "test warning summary", + Detail: "test warning details", + }, + }, + }, + "warning-then-error": { + servers: []func() tfprotov5.ProviderServer{ + (&tf5testserver.TestServer{ + GetResourceIdentityResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ + Diagnostics: []*tfprotov5.Diagnostic{ + { + Severity: tfprotov5.DiagnosticSeverityWarning, + Summary: "test warning summary", + Detail: "test warning details", + }, + }, + }, + }).ProviderServer, + (&tf5testserver.TestServer{}).ProviderServer, + (&tf5testserver.TestServer{ + GetResourceIdentityResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ + Diagnostics: []*tfprotov5.Diagnostic{ + { + Severity: tfprotov5.DiagnosticSeverityError, + Summary: "test error summary", + Detail: "test error details", + }, + }, + }, + }).ProviderServer, + }, + expectedDiagnostics: []*tfprotov5.Diagnostic{ + { + Severity: tfprotov5.DiagnosticSeverityWarning, + Summary: "test warning summary", + Detail: "test warning details", + }, + { + Severity: tfprotov5.DiagnosticSeverityError, + Summary: "test error summary", + Detail: "test error details", + }, + }, + expectedIdentitySchemas: map[string]*tfprotov5.ResourceIdentitySchema{}, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + muxServer, err := tf5muxserver.NewMuxServer(context.Background(), testCase.servers...) + + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + + resourceIdentityServer, ok := muxServer.ProviderServer().(tfprotov5.ProviderServerWithResourceIdentity) + if !ok { + t.Fatal("muxServer should implement tfprotov5.ProviderServerWithResourceIdentity") + } + + resp, err := resourceIdentityServer.GetResourceIdentitySchemas(context.Background(), &tfprotov5.GetResourceIdentitySchemasRequest{}) + + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + + if diff := cmp.Diff(resp.Diagnostics, testCase.expectedDiagnostics); diff != "" { + t.Errorf("diagnostics didn't match expectations: %s", diff) + } + + if diff := cmp.Diff(resp.IdentitySchemas, testCase.expectedIdentitySchemas); diff != "" { + t.Errorf("ephemeral resources schemas didn't match expectations: %s", diff) + } + }) + } +} diff --git a/tf5muxserver/mux_server_UpgradeResourceIdentity.go b/tf5muxserver/mux_server_UpgradeResourceIdentity.go new file mode 100644 index 0000000..34a3717 --- /dev/null +++ b/tf5muxserver/mux_server_UpgradeResourceIdentity.go @@ -0,0 +1,54 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package tf5muxserver + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-go/tfprotov5" + "github.com/hashicorp/terraform-plugin-mux/internal/logging" +) + +// UpgradeResourceState calls the UpgradeResourceState method, passing `req`, +// on the provider that returned the resource specified by req.TypeName in its +// schema. +func (s *muxServer) UpgradeResourceIdentity(ctx context.Context, req *tfprotov5.UpgradeResourceIdentityRequest) (*tfprotov5.UpgradeResourceIdentityResponse, error) { + rpc := "UpgradeResourceIdentity" + ctx = logging.InitContext(ctx) + ctx = logging.RpcContext(ctx, rpc) + + server, diags, err := s.getResourceServer(ctx, req.TypeName) + + if err != nil { + return nil, err + } + + if diagnosticsHasError(diags) { + return &tfprotov5.UpgradeResourceIdentityResponse{ + Diagnostics: diags, + }, nil + } + + // TODO: Remove and call server.UpgradeResourceIdentity below directly once interface becomes required. + resourceIdentityServer, ok := server.(tfprotov5.ProviderServerWithResourceIdentity) + if !ok { + resp := &tfprotov5.UpgradeResourceIdentityResponse{ + Diagnostics: []*tfprotov5.Diagnostic{ + { + Severity: tfprotov5.DiagnosticSeverityError, + Summary: "UpgradeResourceIdentity Not Implemented", + Detail: "A UpgradeResourceIdentity call was received by the provider, however the provider does not implement UpgradeResourceIdentity. " + + "Either upgrade the provider to a version that implements UpgradeResourceIdentity or this is a bug in Terraform that should be reported to the Terraform maintainers.", + }, + }, + } + + return resp, nil + } + + ctx = logging.Tfprotov5ProviderServerContext(ctx, server) + logging.MuxTrace(ctx, "calling downstream server") + + return resourceIdentityServer.UpgradeResourceIdentity(ctx, req) +} diff --git a/tf5muxserver/mux_server_UpgradeResourceIdentity_test.go b/tf5muxserver/mux_server_UpgradeResourceIdentity_test.go new file mode 100644 index 0000000..ed3a0ff --- /dev/null +++ b/tf5muxserver/mux_server_UpgradeResourceIdentity_test.go @@ -0,0 +1,79 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package tf5muxserver_test + +import ( + "context" + "testing" + + "github.com/hashicorp/terraform-plugin-go/tfprotov5" + + "github.com/hashicorp/terraform-plugin-mux/internal/tf5testserver" + "github.com/hashicorp/terraform-plugin-mux/tf5muxserver" +) + +func TestMuxServerUpgradeResourceIdentity(t *testing.T) { + t.Parallel() + + ctx := context.Background() + testServer1 := &tf5testserver.TestServer{ + GetProviderSchemaResponse: &tfprotov5.GetProviderSchemaResponse{ + ResourceSchemas: map[string]*tfprotov5.Schema{ + "test_resource_server1": {}, + }, + }, + } + testServer2 := &tf5testserver.TestServer{ + GetProviderSchemaResponse: &tfprotov5.GetProviderSchemaResponse{ + ResourceSchemas: map[string]*tfprotov5.Schema{ + "test_resource_server2": {}, + }, + }, + } + + servers := []func() tfprotov5.ProviderServer{testServer1.ProviderServer, testServer2.ProviderServer} + muxServer, err := tf5muxserver.NewMuxServer(ctx, servers...) + + if err != nil { + t.Fatalf("unexpected error setting up factory: %s", err) + } + + //_, err = muxServer.ProviderServer().UpgradeResourceIdentity(ctx, &tfprotov5.UpgradeResourceIdentityRequest{ + resourceIdentityServer, ok := muxServer.ProviderServer().(tfprotov5.ProviderServerWithResourceIdentity) + if !ok { + t.Fatal("muxServer should implement tfprotov5.ProviderServerWithEphemeralResources") + } + + _, err = resourceIdentityServer.UpgradeResourceIdentity(ctx, &tfprotov5.UpgradeResourceIdentityRequest{ + TypeName: "test_resource_server1", + }) + + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + + if !testServer1.UpgradeResourceIdentityCalled["test_resource_server1"] { + t.Errorf("expected test_resource_server1 UpgradeResourceIdentity to be called on server1") + } + + if testServer2.UpgradeResourceIdentityCalled["test_resource_server1"] { + t.Errorf("unexpected test_resource_server1 UpgradeResourceIdentity called on server2") + } + + _, err = resourceIdentityServer.UpgradeResourceIdentity(ctx, &tfprotov5.UpgradeResourceIdentityRequest{ + TypeName: "test_resource_server2", + }) + + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + + if testServer1.UpgradeResourceIdentityCalled["test_resource_server2"] { + t.Errorf("unexpected test_resource_server2 UpgradeResourceIdentity called on server1") + } + + if !testServer2.UpgradeResourceIdentityCalled["test_resource_server2"] { + t.Errorf("expected test_resource_server2 UpgradeResourceIdentity to be called on server2") + } +} From 26efadd0cabdb4732a57df0aec7ce558068ee306 Mon Sep 17 00:00:00 2001 From: Rain Date: Tue, 11 Feb 2025 01:58:12 -0500 Subject: [PATCH 02/25] Fixed a bug to get a test to pass --- tf5muxserver/diagnostics.go | 22 ++++++++++++ tf5muxserver/mux_server.go | 35 +++++++++++++++++++ .../mux_server_GetResourceIdentitySchemas.go | 2 +- ..._server_GetResourceIdentitySchemas_test.go | 2 +- .../mux_server_UpgradeResourceIdentity.go | 2 +- 5 files changed, 60 insertions(+), 3 deletions(-) diff --git a/tf5muxserver/diagnostics.go b/tf5muxserver/diagnostics.go index e0761ff..78ccdbb 100644 --- a/tf5muxserver/diagnostics.go +++ b/tf5muxserver/diagnostics.go @@ -94,6 +94,28 @@ func resourceDuplicateError(typeName string) *tfprotov5.Diagnostic { } func resourceMissingError(typeName string) *tfprotov5.Diagnostic { + return &tfprotov5.Diagnostic{ + Severity: tfprotov5.DiagnosticSeverityError, + Summary: "Invalid Provider Server Combination", + Detail: "The combined provider has multiple implementations of the same resource type across underlying providers. " + + "Resource types must be implemented by only one underlying provider. " + + "This is always an issue in the provider implementation and should be reported to the provider developers.\n\n" + + "Duplicate resource type: " + typeName, + } +} + +func resourceIdentityDuplicateError(typeName string) *tfprotov5.Diagnostic { + return &tfprotov5.Diagnostic{ + Severity: tfprotov5.DiagnosticSeverityError, + Summary: "Invalid Provider Server Combination", + Detail: "The combined provider has multiple implementations of the same data source type across underlying providers. " + + "Data source types must be implemented by only one underlying provider. " + + "This is always an issue in the provider implementation and should be reported to the provider developers.\n\n" + + "Duplicate data source type: " + typeName, + } +} + +func resourceIdentityMissingError(typeName string) *tfprotov5.Diagnostic { return &tfprotov5.Diagnostic{ Severity: tfprotov5.DiagnosticSeverityError, Summary: "Resource Not Implemented", diff --git a/tf5muxserver/mux_server.go b/tf5muxserver/mux_server.go index f376f10..ae94960 100644 --- a/tf5muxserver/mux_server.go +++ b/tf5muxserver/mux_server.go @@ -167,6 +167,41 @@ func (s *muxServer) getFunctionServer(ctx context.Context, name string) (tfproto return server, s.serverDiscoveryDiagnostics, nil } +func (s *muxServer) getIdentityResourceServer(ctx context.Context, typeName string) (tfprotov5.ProviderServer, []*tfprotov5.Diagnostic, error) { + s.serverDiscoveryMutex.RLock() + server, ok := s.resourceIdentity[typeName] + discoveryComplete := s.serverDiscoveryComplete + s.serverDiscoveryMutex.RUnlock() + + if discoveryComplete { + if ok { + return server, s.serverDiscoveryDiagnostics, nil + } + + return nil, []*tfprotov5.Diagnostic{ + resourceIdentityMissingError(typeName), + }, nil + } + + err := s.serverDiscovery(ctx) + + if err != nil || diagnosticsHasError(s.serverDiscoveryDiagnostics) { + return nil, s.serverDiscoveryDiagnostics, err + } + + s.serverDiscoveryMutex.RLock() + server, ok = s.resourceIdentity[typeName] + s.serverDiscoveryMutex.RUnlock() + + if !ok { + return nil, []*tfprotov5.Diagnostic{ + resourceIdentityMissingError(typeName), + }, nil + } + + return server, s.serverDiscoveryDiagnostics, nil +} + func (s *muxServer) getResourceServer(ctx context.Context, typeName string) (tfprotov5.ProviderServer, []*tfprotov5.Diagnostic, error) { s.serverDiscoveryMutex.RLock() server, ok := s.resources[typeName] diff --git a/tf5muxserver/mux_server_GetResourceIdentitySchemas.go b/tf5muxserver/mux_server_GetResourceIdentitySchemas.go index 7775b32..5bc1d0a 100644 --- a/tf5muxserver/mux_server_GetResourceIdentitySchemas.go +++ b/tf5muxserver/mux_server_GetResourceIdentitySchemas.go @@ -43,7 +43,7 @@ func (s *muxServer) GetResourceIdentitySchemas(ctx context.Context, req *tfproto for resourceIdentityType, schema := range resourceIdentityServer.IdentitySchemas { if _, ok := resp.IdentitySchemas[resourceIdentityType]; ok { - resp.Diagnostics = append(resp.Diagnostics, ephemeralResourceDuplicateError(resourceIdentityType)) + resp.Diagnostics = append(resp.Diagnostics, resourceIdentityDuplicateError(resourceIdentityType)) continue } diff --git a/tf5muxserver/mux_server_GetResourceIdentitySchemas_test.go b/tf5muxserver/mux_server_GetResourceIdentitySchemas_test.go index f084781..b318e9d 100644 --- a/tf5muxserver/mux_server_GetResourceIdentitySchemas_test.go +++ b/tf5muxserver/mux_server_GetResourceIdentitySchemas_test.go @@ -363,7 +363,7 @@ func TestMuxServerGetResourceIdentitySchema(t *testing.T) { } if diff := cmp.Diff(resp.IdentitySchemas, testCase.expectedIdentitySchemas); diff != "" { - t.Errorf("ephemeral resources schemas didn't match expectations: %s", diff) + t.Errorf("identity schemas didn't match expectations: %s", diff) } }) } diff --git a/tf5muxserver/mux_server_UpgradeResourceIdentity.go b/tf5muxserver/mux_server_UpgradeResourceIdentity.go index 34a3717..bed5d85 100644 --- a/tf5muxserver/mux_server_UpgradeResourceIdentity.go +++ b/tf5muxserver/mux_server_UpgradeResourceIdentity.go @@ -18,7 +18,7 @@ func (s *muxServer) UpgradeResourceIdentity(ctx context.Context, req *tfprotov5. ctx = logging.InitContext(ctx) ctx = logging.RpcContext(ctx, rpc) - server, diags, err := s.getResourceServer(ctx, req.TypeName) + server, diags, err := s.getIdentityResourceServer(ctx, req.TypeName) if err != nil { return nil, err From a90c989661d92292a16e0683f599b8fead20d27e Mon Sep 17 00:00:00 2001 From: Rain Date: Tue, 11 Feb 2025 01:58:12 -0500 Subject: [PATCH 03/25] Fixed a bug to get a test to pass --- tf5muxserver/mux_server_UpgradeResourceIdentity_test.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tf5muxserver/mux_server_UpgradeResourceIdentity_test.go b/tf5muxserver/mux_server_UpgradeResourceIdentity_test.go index ed3a0ff..19b6d1b 100644 --- a/tf5muxserver/mux_server_UpgradeResourceIdentity_test.go +++ b/tf5muxserver/mux_server_UpgradeResourceIdentity_test.go @@ -18,15 +18,15 @@ func TestMuxServerUpgradeResourceIdentity(t *testing.T) { ctx := context.Background() testServer1 := &tf5testserver.TestServer{ - GetProviderSchemaResponse: &tfprotov5.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfprotov5.Schema{ + GetResourceIdentityResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ + IdentitySchemas: map[string]*tfprotov5.ResourceIdentitySchema{ "test_resource_server1": {}, }, }, } testServer2 := &tf5testserver.TestServer{ - GetProviderSchemaResponse: &tfprotov5.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfprotov5.Schema{ + GetResourceIdentityResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ + IdentitySchemas: map[string]*tfprotov5.ResourceIdentitySchema{ "test_resource_server2": {}, }, }, @@ -39,7 +39,6 @@ func TestMuxServerUpgradeResourceIdentity(t *testing.T) { t.Fatalf("unexpected error setting up factory: %s", err) } - //_, err = muxServer.ProviderServer().UpgradeResourceIdentity(ctx, &tfprotov5.UpgradeResourceIdentityRequest{ resourceIdentityServer, ok := muxServer.ProviderServer().(tfprotov5.ProviderServerWithResourceIdentity) if !ok { t.Fatal("muxServer should implement tfprotov5.ProviderServerWithEphemeralResources") From 89cdb3de396ce3f1f006b14b3d0c91ab3615c282 Mon Sep 17 00:00:00 2001 From: Ansgar Mertens Date: Tue, 11 Feb 2025 10:55:45 +0100 Subject: [PATCH 04/25] populate resourceIdentity map in serverDiscovery and pass a schema with resource to UpgradeResourceIdentity tests so they can lookup the right server for that rpc --- tf5muxserver/mux_server.go | 5 +++++ .../mux_server_UpgradeResourceIdentity_test.go | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/tf5muxserver/mux_server.go b/tf5muxserver/mux_server.go index ae94960..ae546b3 100644 --- a/tf5muxserver/mux_server.go +++ b/tf5muxserver/mux_server.go @@ -307,6 +307,9 @@ func (s *muxServer) serverDiscovery(ctx context.Context) error { s.resources[serverResource.TypeName] = server s.resourceCapabilities[serverResource.TypeName] = metadataResp.ServerCapabilities + + // Resource identity is expected to be implemented in the same server as the resource + s.resourceIdentity[serverResource.TypeName] = server } continue @@ -369,6 +372,8 @@ func (s *muxServer) serverDiscovery(ctx context.Context) error { s.resources[typeName] = server s.resourceCapabilities[typeName] = providerSchemaResp.ServerCapabilities + // Resource identity is expected to be implemented in the same server as the resource + s.resourceIdentity[typeName] = server } } diff --git a/tf5muxserver/mux_server_UpgradeResourceIdentity_test.go b/tf5muxserver/mux_server_UpgradeResourceIdentity_test.go index 19b6d1b..b338f35 100644 --- a/tf5muxserver/mux_server_UpgradeResourceIdentity_test.go +++ b/tf5muxserver/mux_server_UpgradeResourceIdentity_test.go @@ -23,6 +23,11 @@ func TestMuxServerUpgradeResourceIdentity(t *testing.T) { "test_resource_server1": {}, }, }, + GetProviderSchemaResponse: &tfprotov5.GetProviderSchemaResponse{ + ResourceSchemas: map[string]*tfprotov5.Schema{ + "test_resource_server1": {}, + }, + }, } testServer2 := &tf5testserver.TestServer{ GetResourceIdentityResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ @@ -30,6 +35,11 @@ func TestMuxServerUpgradeResourceIdentity(t *testing.T) { "test_resource_server2": {}, }, }, + GetProviderSchemaResponse: &tfprotov5.GetProviderSchemaResponse{ + ResourceSchemas: map[string]*tfprotov5.Schema{ + "test_resource_server2": {}, + }, + }, } servers := []func() tfprotov5.ProviderServer{testServer1.ProviderServer, testServer2.ProviderServer} From 10b6df20ba414cd2aa68cbdc0be63900d70e7488 Mon Sep 17 00:00:00 2001 From: Ansgar Mertens Date: Tue, 11 Feb 2025 12:05:51 +0100 Subject: [PATCH 05/25] fix copy paste wording for new error --- tf5muxserver/diagnostics.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tf5muxserver/diagnostics.go b/tf5muxserver/diagnostics.go index 78ccdbb..c8e4666 100644 --- a/tf5muxserver/diagnostics.go +++ b/tf5muxserver/diagnostics.go @@ -108,10 +108,10 @@ func resourceIdentityDuplicateError(typeName string) *tfprotov5.Diagnostic { return &tfprotov5.Diagnostic{ Severity: tfprotov5.DiagnosticSeverityError, Summary: "Invalid Provider Server Combination", - Detail: "The combined provider has multiple implementations of the same data source type across underlying providers. " + - "Data source types must be implemented by only one underlying provider. " + + Detail: "The combined provider has multiple implementations of the same resource identity across underlying providers. " + + "Resource identity types must be implemented by only one underlying provider. " + "This is always an issue in the provider implementation and should be reported to the provider developers.\n\n" + - "Duplicate data source type: " + typeName, + "Duplicate identity type for resource: " + typeName, } } From 300093d5371c163cc3a6b83c52ab8b1a8db1a398 Mon Sep 17 00:00:00 2001 From: Ansgar Mertens Date: Tue, 11 Feb 2025 12:15:39 +0100 Subject: [PATCH 06/25] fix error message that was accidentally changed --- tf5muxserver/diagnostics.go | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/tf5muxserver/diagnostics.go b/tf5muxserver/diagnostics.go index c8e4666..b5818cc 100644 --- a/tf5muxserver/diagnostics.go +++ b/tf5muxserver/diagnostics.go @@ -96,11 +96,10 @@ func resourceDuplicateError(typeName string) *tfprotov5.Diagnostic { func resourceMissingError(typeName string) *tfprotov5.Diagnostic { return &tfprotov5.Diagnostic{ Severity: tfprotov5.DiagnosticSeverityError, - Summary: "Invalid Provider Server Combination", - Detail: "The combined provider has multiple implementations of the same resource type across underlying providers. " + - "Resource types must be implemented by only one underlying provider. " + + Summary: "Resource Not Implemented", + Detail: "The combined provider does not implement the requested resource type. " + "This is always an issue in the provider implementation and should be reported to the provider developers.\n\n" + - "Duplicate resource type: " + typeName, + "Missing resource type: " + typeName, } } @@ -118,9 +117,9 @@ func resourceIdentityDuplicateError(typeName string) *tfprotov5.Diagnostic { func resourceIdentityMissingError(typeName string) *tfprotov5.Diagnostic { return &tfprotov5.Diagnostic{ Severity: tfprotov5.DiagnosticSeverityError, - Summary: "Resource Not Implemented", - Detail: "The combined provider does not implement the requested resource type. " + + Summary: "Resource Identity Not Implemented", + Detail: "The combined provider does not implement the requested resource identity type. " + "This is always an issue in the provider implementation and should be reported to the provider developers.\n\n" + - "Missing resource type: " + typeName, + "Missing identity type for resource: " + typeName, } } From 0473cdd53fc53c64844d75e957484f4bd541cc72 Mon Sep 17 00:00:00 2001 From: Ansgar Mertens Date: Tue, 11 Feb 2025 12:25:28 +0100 Subject: [PATCH 07/25] fix GetResourceIdentitySchemas test --- .../mux_server_GetResourceIdentitySchemas_test.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tf5muxserver/mux_server_GetResourceIdentitySchemas_test.go b/tf5muxserver/mux_server_GetResourceIdentitySchemas_test.go index b318e9d..3061b1f 100644 --- a/tf5muxserver/mux_server_GetResourceIdentitySchemas_test.go +++ b/tf5muxserver/mux_server_GetResourceIdentitySchemas_test.go @@ -26,7 +26,6 @@ func TestMuxServerGetResourceIdentitySchema(t *testing.T) { servers: []func() tfprotov5.ProviderServer{ (&tf5testserver.TestServer{ GetResourceIdentityResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ - Diagnostics: []*tfprotov5.Diagnostic{}, IdentitySchemas: map[string]*tfprotov5.ResourceIdentitySchema{ "test_resource_identity_foo": { Version: 1, @@ -63,7 +62,6 @@ func TestMuxServerGetResourceIdentitySchema(t *testing.T) { }).ProviderServer, (&tf5testserver.TestServer{ GetResourceIdentityResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ - Diagnostics: []*tfprotov5.Diagnostic{}, IdentitySchemas: map[string]*tfprotov5.ResourceIdentitySchema{ "test_resource_identity_foobar": { Version: 1, @@ -131,6 +129,7 @@ func TestMuxServerGetResourceIdentitySchema(t *testing.T) { }, }, }, + expectedDiagnostics: []*tfprotov5.Diagnostic{}, }, "duplicate-identity-schema-type": { servers: []func() tfprotov5.ProviderServer{ @@ -156,10 +155,10 @@ func TestMuxServerGetResourceIdentitySchema(t *testing.T) { { Severity: tfprotov5.DiagnosticSeverityError, Summary: "Invalid Provider Server Combination", - Detail: "The combined provider has multiple implementations of the same data source type across underlying providers. " + - "Data source types must be implemented by only one underlying provider. " + + Detail: "The combined provider has multiple implementations of the same resource identity across underlying providers. " + + "Resource identity types must be implemented by only one underlying provider. " + "This is always an issue in the provider implementation and should be reported to the provider developers.\n\n" + - "Duplicate data source type: test_foo", + "Duplicate identity type for resource: test_foo", }, }, }, From 45960d4118d2cb1b8808bb9114fb5c2dba4e407e Mon Sep 17 00:00:00 2001 From: Ansgar Mertens Date: Tue, 11 Feb 2025 15:15:14 +0100 Subject: [PATCH 08/25] add resource identity mapping support to tfprotov5tov6 --- internal/tfprotov5tov6/tfprotov5tov6.go | 131 +++++- internal/tfprotov5tov6/tfprotov5tov6_test.go | 452 +++++++++++++++++-- 2 files changed, 537 insertions(+), 46 deletions(-) diff --git a/internal/tfprotov5tov6/tfprotov5tov6.go b/internal/tfprotov5tov6/tfprotov5tov6.go index 12f1478..ab313b0 100644 --- a/internal/tfprotov5tov6/tfprotov5tov6.go +++ b/internal/tfprotov5tov6/tfprotov5tov6.go @@ -14,12 +14,13 @@ func ApplyResourceChangeRequest(in *tfprotov5.ApplyResourceChangeRequest) *tfpro } return &tfprotov6.ApplyResourceChangeRequest{ - Config: DynamicValue(in.Config), - PlannedPrivate: in.PlannedPrivate, - PlannedState: DynamicValue(in.PlannedState), - PriorState: DynamicValue(in.PriorState), - ProviderMeta: DynamicValue(in.ProviderMeta), - TypeName: in.TypeName, + Config: DynamicValue(in.Config), + PlannedPrivate: in.PlannedPrivate, + PlannedState: DynamicValue(in.PlannedState), + PriorState: DynamicValue(in.PriorState), + ProviderMeta: DynamicValue(in.ProviderMeta), + TypeName: in.TypeName, + PlannedIdentity: ResourceIdentityData(in.PlannedIdentity), } } @@ -33,6 +34,7 @@ func ApplyResourceChangeResponse(in *tfprotov5.ApplyResourceChangeResponse) *tfp NewState: DynamicValue(in.NewState), Private: in.Private, UnsafeToUseLegacyTypeSystem: in.UnsafeToUseLegacyTypeSystem, //nolint:staticcheck + NewIdentity: ResourceIdentityData(in.NewIdentity), } } @@ -172,6 +174,16 @@ func DynamicValue(in *tfprotov5.DynamicValue) *tfprotov6.DynamicValue { } } +func ResourceIdentityData(in *tfprotov5.ResourceIdentityData) *tfprotov6.ResourceIdentityData { + if in == nil { + return nil + } + + return &tfprotov6.ResourceIdentityData{ + IdentityData: DynamicValue(in.IdentityData), + } +} + func EphemeralResourceMetadata(in tfprotov5.EphemeralResourceMetadata) tfprotov6.EphemeralResourceMetadata { return tfprotov6.EphemeralResourceMetadata{ TypeName: in.TypeName, @@ -359,6 +371,31 @@ func GetProviderSchemaResponse(in *tfprotov5.GetProviderSchemaResponse) *tfproto } } +func GetResourceIdentitySchemasRequest(in *tfprotov5.GetResourceIdentitySchemasRequest) *tfprotov6.GetResourceIdentitySchemasRequest { + if in == nil { + return nil + } + + return &tfprotov6.GetResourceIdentitySchemasRequest{} +} + +func GetResourceIdentitySchemasResponse(in *tfprotov5.GetResourceIdentitySchemasResponse) *tfprotov6.GetResourceIdentitySchemasResponse { + if in == nil { + return nil + } + + identitySchemas := make(map[string]*tfprotov6.ResourceIdentitySchema, len(in.IdentitySchemas)) + + for k, v := range in.IdentitySchemas { + identitySchemas[k] = ResourceIdentitySchema(v) + } + + return &tfprotov6.GetResourceIdentitySchemasResponse{ + Diagnostics: Diagnostics(in.Diagnostics), + IdentitySchemas: identitySchemas, + } +} + func ImportResourceStateRequest(in *tfprotov5.ImportResourceStateRequest) *tfprotov6.ImportResourceStateRequest { if in == nil { return nil @@ -368,6 +405,7 @@ func ImportResourceStateRequest(in *tfprotov5.ImportResourceStateRequest) *tfpro ClientCapabilities: ImportResourceStateClientCapabilities(in.ClientCapabilities), ID: in.ID, TypeName: in.TypeName, + Identity: ResourceIdentityData(in.Identity), } } @@ -412,6 +450,7 @@ func ImportedResources(in []*tfprotov5.ImportedResource) []*tfprotov6.ImportedRe Private: imp.Private, State: DynamicValue(imp.State), TypeName: imp.TypeName, + Identity: ResourceIdentityData(imp.Identity), }) } @@ -430,6 +469,7 @@ func MoveResourceStateRequest(in *tfprotov5.MoveResourceStateRequest) *tfprotov6 SourceState: RawState(in.SourceState), SourceTypeName: in.SourceTypeName, TargetTypeName: in.TargetTypeName, + SourceIdentity: ResourceIdentityData(in.SourceIdentity), } } @@ -439,9 +479,10 @@ func MoveResourceStateResponse(in *tfprotov5.MoveResourceStateResponse) *tfproto } return &tfprotov6.MoveResourceStateResponse{ - Diagnostics: Diagnostics(in.Diagnostics), - TargetPrivate: in.TargetPrivate, - TargetState: DynamicValue(in.TargetState), + Diagnostics: Diagnostics(in.Diagnostics), + TargetPrivate: in.TargetPrivate, + TargetState: DynamicValue(in.TargetState), + TargetIdentity: ResourceIdentityData(in.TargetIdentity), } } @@ -496,6 +537,7 @@ func PlanResourceChangeRequest(in *tfprotov5.PlanResourceChangeRequest) *tfproto ProposedNewState: DynamicValue(in.ProposedNewState), ProviderMeta: DynamicValue(in.ProviderMeta), TypeName: in.TypeName, + PriorIdentity: ResourceIdentityData(in.PriorIdentity), } } @@ -523,6 +565,7 @@ func PlanResourceChangeResponse(in *tfprotov5.PlanResourceChangeResponse) *tfpro PlannedState: DynamicValue(in.PlannedState), RequiresReplace: in.RequiresReplace, UnsafeToUseLegacyTypeSystem: in.UnsafeToUseLegacyTypeSystem, //nolint:staticcheck + PlannedIdentity: ResourceIdentityData(in.PlannedIdentity), } } @@ -537,6 +580,16 @@ func RawState(in *tfprotov5.RawState) *tfprotov6.RawState { } } +func RawIdentity(in *tfprotov5.RawIdentity) *tfprotov6.RawIdentity { + if in == nil { + return nil + } + + return &tfprotov6.RawIdentity{ + JSON: in.JSON, + } +} + func ReadDataSourceRequest(in *tfprotov5.ReadDataSourceRequest) *tfprotov6.ReadDataSourceRequest { if in == nil { return nil @@ -584,6 +637,7 @@ func ReadResourceRequest(in *tfprotov5.ReadResourceRequest) *tfprotov6.ReadResou Private: in.Private, ProviderMeta: DynamicValue(in.ProviderMeta), TypeName: in.TypeName, + CurrentIdentity: ResourceIdentityData(in.CurrentIdentity), } } @@ -609,6 +663,7 @@ func ReadResourceResponse(in *tfprotov5.ReadResourceResponse) *tfprotov6.ReadRes Diagnostics: Diagnostics(in.Diagnostics), NewState: DynamicValue(in.NewState), Private: in.Private, + NewIdentity: ResourceIdentityData(in.NewIdentity), } } @@ -720,6 +775,41 @@ func SchemaNestedBlock(in *tfprotov5.SchemaNestedBlock) *tfprotov6.SchemaNestedB } } +func ResourceIdentitySchema(in *tfprotov5.ResourceIdentitySchema) *tfprotov6.ResourceIdentitySchema { + if in == nil { + return nil + } + + var attrs []*tfprotov6.ResourceIdentitySchemaAttribute + + if in.IdentityAttributes != nil { + attrs = make([]*tfprotov6.ResourceIdentitySchemaAttribute, 0, len(in.IdentityAttributes)) + + for _, attr := range in.IdentityAttributes { + attrs = append(attrs, ResourceIdentitySchemaAttribute(attr)) + } + } + + return &tfprotov6.ResourceIdentitySchema{ + Version: in.Version, + IdentityAttributes: attrs, + } +} + +func ResourceIdentitySchemaAttribute(in *tfprotov5.ResourceIdentitySchemaAttribute) *tfprotov6.ResourceIdentitySchemaAttribute { + if in == nil { + return nil + } + + return &tfprotov6.ResourceIdentitySchemaAttribute{ + Name: in.Name, + Type: in.Type, + RequiredForImport: in.RequiredForImport, + OptionalForImport: in.OptionalForImport, + Description: in.Description, + } +} + func ServerCapabilities(in *tfprotov5.ServerCapabilities) *tfprotov6.ServerCapabilities { if in == nil { return nil @@ -777,6 +867,29 @@ func UpgradeResourceStateResponse(in *tfprotov5.UpgradeResourceStateResponse) *t } } +func UpgradeResourceIdentityRequest(in *tfprotov5.UpgradeResourceIdentityRequest) *tfprotov6.UpgradeResourceIdentityRequest { + if in == nil { + return nil + } + + return &tfprotov6.UpgradeResourceIdentityRequest{ + TypeName: in.TypeName, + Version: in.Version, + RawIdentity: RawIdentity(in.RawIdentity), + } +} + +func UpgradeResourceIdentityResponse(in *tfprotov5.UpgradeResourceIdentityResponse) *tfprotov6.UpgradeResourceIdentityResponse { + if in == nil { + return nil + } + + return &tfprotov6.UpgradeResourceIdentityResponse{ + Diagnostics: Diagnostics(in.Diagnostics), + UpgradedIdentity: ResourceIdentityData(in.UpgradedIdentity), + } +} + func ValidateEphemeralResourceConfigRequest(in *tfprotov5.ValidateEphemeralResourceConfigRequest) *tfprotov6.ValidateEphemeralResourceConfigRequest { if in == nil { return nil diff --git a/internal/tfprotov5tov6/tfprotov5tov6_test.go b/internal/tfprotov5tov6/tfprotov5tov6_test.go index 71b2993..9bfd035 100644 --- a/internal/tfprotov5tov6/tfprotov5tov6_test.go +++ b/internal/tfprotov5tov6/tfprotov5tov6_test.go @@ -44,6 +44,9 @@ var ( testTfprotov5DynamicValue tfprotov5.DynamicValue testTfprotov6DynamicValue tfprotov6.DynamicValue + testTfprotov5ResourceIdentityData tfprotov5.ResourceIdentityData + testTfprotov6ResourceIdentityData tfprotov6.ResourceIdentityData + testTfprotov5EphemeralResourceMetadata tfprotov5.EphemeralResourceMetadata = tfprotov5.EphemeralResourceMetadata{ TypeName: "test_ephemeral_resource", } @@ -117,12 +120,53 @@ var ( Version: 1, } + testTfprotov5ResourceIdentitySchema *tfprotov5.ResourceIdentitySchema = &tfprotov5.ResourceIdentitySchema{ + Version: 1, + IdentityAttributes: []*tfprotov5.ResourceIdentitySchemaAttribute{ + { + Name: "req", + Type: tftypes.String, + RequiredForImport: true, + Description: "this one's required", + }, + { + Name: "opt", + Type: tftypes.String, + OptionalForImport: true, + Description: "this one's optional", + }, + }, + } + testTfprotov6ResourceIdentitySchema *tfprotov6.ResourceIdentitySchema = &tfprotov6.ResourceIdentitySchema{ + Version: 1, + IdentityAttributes: []*tfprotov6.ResourceIdentitySchemaAttribute{ + { + Name: "req", + Type: tftypes.String, + RequiredForImport: true, + Description: "this one's required", + }, + { + Name: "opt", + Type: tftypes.String, + OptionalForImport: true, + Description: "this one's optional", + }, + }, + } + testTime time.Time = time.Date(2000, 1, 2, 3, 4, 5, 6, time.UTC) ) func init() { testTfprotov5DynamicValue, _ = tfprotov5.NewDynamicValue(tftypes.String, tftypes.NewValue(tftypes.String, "test")) testTfprotov6DynamicValue, _ = tfprotov6.NewDynamicValue(tftypes.String, tftypes.NewValue(tftypes.String, "test")) + testTfprotov5ResourceIdentityData = tfprotov5.ResourceIdentityData{ + IdentityData: &testTfprotov5DynamicValue, + } + testTfprotov6ResourceIdentityData = tfprotov6.ResourceIdentityData{ + IdentityData: &testTfprotov6DynamicValue, + } } func TestApplyResourceChangeRequest(t *testing.T) { @@ -138,20 +182,22 @@ func TestApplyResourceChangeRequest(t *testing.T) { }, "all-valid-fields": { in: &tfprotov5.ApplyResourceChangeRequest{ - Config: &testTfprotov5DynamicValue, - PlannedPrivate: testBytes, - PlannedState: &testTfprotov5DynamicValue, - PriorState: &testTfprotov5DynamicValue, - ProviderMeta: &testTfprotov5DynamicValue, - TypeName: "test", + Config: &testTfprotov5DynamicValue, + PlannedPrivate: testBytes, + PlannedState: &testTfprotov5DynamicValue, + PriorState: &testTfprotov5DynamicValue, + ProviderMeta: &testTfprotov5DynamicValue, + TypeName: "test", + PlannedIdentity: &testTfprotov5ResourceIdentityData, }, expected: &tfprotov6.ApplyResourceChangeRequest{ - Config: &testTfprotov6DynamicValue, - PlannedPrivate: testBytes, - PlannedState: &testTfprotov6DynamicValue, - PriorState: &testTfprotov6DynamicValue, - ProviderMeta: &testTfprotov6DynamicValue, - TypeName: "test", + Config: &testTfprotov6DynamicValue, + PlannedPrivate: testBytes, + PlannedState: &testTfprotov6DynamicValue, + PriorState: &testTfprotov6DynamicValue, + ProviderMeta: &testTfprotov6DynamicValue, + TypeName: "test", + PlannedIdentity: &testTfprotov6ResourceIdentityData, }, }, } @@ -188,12 +234,14 @@ func TestApplyResourceChangeResponse(t *testing.T) { NewState: &testTfprotov5DynamicValue, Private: testBytes, UnsafeToUseLegacyTypeSystem: true, + NewIdentity: &testTfprotov5ResourceIdentityData, }, expected: &tfprotov6.ApplyResourceChangeResponse{ Diagnostics: testTfprotov6Diagnostics, NewState: &testTfprotov6DynamicValue, Private: testBytes, UnsafeToUseLegacyTypeSystem: true, + NewIdentity: &testTfprotov6ResourceIdentityData, }, }, } @@ -557,6 +605,42 @@ func TestDynamicValue(t *testing.T) { } } +func TestResourceIdentityData(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + in *tfprotov5.ResourceIdentityData + expected *tfprotov6.ResourceIdentityData + }{ + "nil": { + in: nil, + expected: nil, + }, + "all-valid-fields": { + in: &tfprotov5.ResourceIdentityData{ + IdentityData: &testTfprotov5DynamicValue, + }, + expected: &tfprotov6.ResourceIdentityData{ + IdentityData: &testTfprotov6DynamicValue, + }, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := tfprotov5tov6.ResourceIdentityData(testCase.in) + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + func TestFunction(t *testing.T) { t.Parallel() @@ -918,7 +1002,7 @@ func TestGetProviderSchemaRequest(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := tfprotov5tov6.GetProviderSchemaRequest(testCase.in) + got := tfprotov5tov6.GetProviderSchemaRequest(testCase.in) // TODO: we need this for GetResourceIdentitySchemas() (or similarly named) if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) @@ -991,6 +1075,80 @@ func TestGetProviderSchemaResponse(t *testing.T) { } } +func TestGetResourceIdentitySchemasRequest(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + in *tfprotov5.GetResourceIdentitySchemasRequest + expected *tfprotov6.GetResourceIdentitySchemasRequest + }{ + "nil": { + in: nil, + expected: nil, + }, + "all-valid-fields": { + in: &tfprotov5.GetResourceIdentitySchemasRequest{}, + expected: &tfprotov6.GetResourceIdentitySchemasRequest{}, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := tfprotov5tov6.GetResourceIdentitySchemasRequest(testCase.in) + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestGetResourceIdentitySchemasResponse(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + in *tfprotov5.GetResourceIdentitySchemasResponse + expected *tfprotov6.GetResourceIdentitySchemasResponse + }{ + "nil": { + in: nil, + expected: nil, + }, + "all-valid-fields": { + in: &tfprotov5.GetResourceIdentitySchemasResponse{ + Diagnostics: testTfprotov5Diagnostics, + IdentitySchemas: map[string]*tfprotov5.ResourceIdentitySchema{ + "test_resource": testTfprotov5ResourceIdentitySchema, + }, + }, + expected: &tfprotov6.GetResourceIdentitySchemasResponse{ + Diagnostics: testTfprotov6Diagnostics, + IdentitySchemas: map[string]*tfprotov6.ResourceIdentitySchema{ + "test_resource": testTfprotov6ResourceIdentitySchema, + }, + }, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := tfprotov5tov6.GetResourceIdentitySchemasResponse(testCase.in) + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + func TestImportResourceStateRequest(t *testing.T) { t.Parallel() @@ -1006,10 +1164,12 @@ func TestImportResourceStateRequest(t *testing.T) { in: &tfprotov5.ImportResourceStateRequest{ ID: "test-id", TypeName: "test_resource", + Identity: &testTfprotov5ResourceIdentityData, }, expected: &tfprotov6.ImportResourceStateRequest{ ID: "test-id", TypeName: "test_resource", + Identity: &testTfprotov6ResourceIdentityData, }, }, "client-capabilities-deferral-allowed": { @@ -1064,6 +1224,7 @@ func TestImportResourceStateResponse(t *testing.T) { Private: testBytes, State: &testTfprotov5DynamicValue, TypeName: "test_resource1", + Identity: &testTfprotov5ResourceIdentityData, }, }, }, @@ -1074,6 +1235,7 @@ func TestImportResourceStateResponse(t *testing.T) { Private: testBytes, State: &testTfprotov6DynamicValue, TypeName: "test_resource1", + Identity: &testTfprotov6ResourceIdentityData, }, }, }, @@ -1144,6 +1306,7 @@ func TestImportedResources(t *testing.T) { Private: testBytes, State: &testTfprotov5DynamicValue, TypeName: "test_resource1", + Identity: &testTfprotov5ResourceIdentityData, }, }, expected: []*tfprotov6.ImportedResource{ @@ -1151,6 +1314,7 @@ func TestImportedResources(t *testing.T) { Private: testBytes, State: &testTfprotov6DynamicValue, TypeName: "test_resource1", + Identity: &testTfprotov6ResourceIdentityData, }, }, }, @@ -1219,6 +1383,7 @@ func TestMoveResourceStateRequest(t *testing.T) { }, SourceTypeName: "test_source", TargetTypeName: "test_target", + SourceIdentity: &testTfprotov5ResourceIdentityData, }, expected: &tfprotov6.MoveResourceStateRequest{ SourcePrivate: testBytes, @@ -1229,6 +1394,7 @@ func TestMoveResourceStateRequest(t *testing.T) { }, SourceTypeName: "test_source", TargetTypeName: "test_target", + SourceIdentity: &testTfprotov6ResourceIdentityData, }, }, } @@ -1261,14 +1427,16 @@ func TestMoveResourceStateResponse(t *testing.T) { }, "all-valid-fields": { in: &tfprotov5.MoveResourceStateResponse{ - Diagnostics: testTfprotov5Diagnostics, - TargetPrivate: testBytes, - TargetState: &testTfprotov5DynamicValue, + Diagnostics: testTfprotov5Diagnostics, + TargetPrivate: testBytes, + TargetState: &testTfprotov5DynamicValue, + TargetIdentity: &testTfprotov5ResourceIdentityData, }, expected: &tfprotov6.MoveResourceStateResponse{ - Diagnostics: testTfprotov6Diagnostics, - TargetState: &testTfprotov6DynamicValue, - TargetPrivate: testBytes, + Diagnostics: testTfprotov6Diagnostics, + TargetState: &testTfprotov6DynamicValue, + TargetPrivate: testBytes, + TargetIdentity: &testTfprotov6ResourceIdentityData, }, }, } @@ -1419,6 +1587,7 @@ func TestPlanResourceChangeRequest(t *testing.T) { ProposedNewState: &testTfprotov5DynamicValue, ProviderMeta: &testTfprotov5DynamicValue, TypeName: "test_resource", + PriorIdentity: &testTfprotov5ResourceIdentityData, }, expected: &tfprotov6.PlanResourceChangeRequest{ Config: &testTfprotov6DynamicValue, @@ -1427,6 +1596,7 @@ func TestPlanResourceChangeRequest(t *testing.T) { ProposedNewState: &testTfprotov6DynamicValue, ProviderMeta: &testTfprotov6DynamicValue, TypeName: "test_resource", + PriorIdentity: &testTfprotov6ResourceIdentityData, }, }, "client-capabilities-deferral-allowed": { @@ -1437,6 +1607,7 @@ func TestPlanResourceChangeRequest(t *testing.T) { ProposedNewState: &testTfprotov5DynamicValue, ProviderMeta: &testTfprotov5DynamicValue, TypeName: "test_resource", + PriorIdentity: &testTfprotov5ResourceIdentityData, ClientCapabilities: &tfprotov5.PlanResourceChangeClientCapabilities{ DeferralAllowed: true, }, @@ -1448,6 +1619,7 @@ func TestPlanResourceChangeRequest(t *testing.T) { ProposedNewState: &testTfprotov6DynamicValue, ProviderMeta: &testTfprotov6DynamicValue, TypeName: "test_resource", + PriorIdentity: &testTfprotov6ResourceIdentityData, ClientCapabilities: &tfprotov6.PlanResourceChangeClientCapabilities{ DeferralAllowed: true, }, @@ -1490,6 +1662,7 @@ func TestPlanResourceChangeResponse(t *testing.T) { tftypes.NewAttributePath().WithAttributeName("test"), }, UnsafeToUseLegacyTypeSystem: true, + PlannedIdentity: &testTfprotov5ResourceIdentityData, }, expected: &tfprotov6.PlanResourceChangeResponse{ Diagnostics: testTfprotov6Diagnostics, @@ -1499,6 +1672,7 @@ func TestPlanResourceChangeResponse(t *testing.T) { tftypes.NewAttributePath().WithAttributeName("test"), }, UnsafeToUseLegacyTypeSystem: true, + PlannedIdentity: &testTfprotov6ResourceIdentityData, }, }, "deferred-reason": { @@ -1510,6 +1684,7 @@ func TestPlanResourceChangeResponse(t *testing.T) { tftypes.NewAttributePath().WithAttributeName("test"), }, UnsafeToUseLegacyTypeSystem: true, + PlannedIdentity: &testTfprotov5ResourceIdentityData, Deferred: &tfprotov5.Deferred{ Reason: tfprotov5.DeferredReasonResourceConfigUnknown, }, @@ -1522,6 +1697,7 @@ func TestPlanResourceChangeResponse(t *testing.T) { tftypes.NewAttributePath().WithAttributeName("test"), }, UnsafeToUseLegacyTypeSystem: true, + PlannedIdentity: &testTfprotov6ResourceIdentityData, Deferred: &tfprotov6.Deferred{ Reason: tfprotov6.DeferredReasonResourceConfigUnknown, }, @@ -1573,7 +1749,43 @@ func TestRawState(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := tfprotov5tov6.RawState(testCase.in) + got := tfprotov5tov6.RawState(testCase.in) // TODO: we need this for raw identity + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestRawIdentity(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + in *tfprotov5.RawIdentity + expected *tfprotov6.RawIdentity + }{ + "nil": { + in: nil, + expected: nil, + }, + "all-valid-fields": { + in: &tfprotov5.RawIdentity{ + JSON: testBytes, + }, + expected: &tfprotov6.RawIdentity{ + JSON: testBytes, + }, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := tfprotov5tov6.RawIdentity(testCase.in) if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) @@ -1707,33 +1919,37 @@ func TestReadResourceRequest(t *testing.T) { }, "all-valid-fields": { in: &tfprotov5.ReadResourceRequest{ - CurrentState: &testTfprotov5DynamicValue, - Private: testBytes, - ProviderMeta: &testTfprotov5DynamicValue, - TypeName: "test_resource", + CurrentState: &testTfprotov5DynamicValue, + Private: testBytes, + ProviderMeta: &testTfprotov5DynamicValue, + TypeName: "test_resource", + CurrentIdentity: &testTfprotov5ResourceIdentityData, }, expected: &tfprotov6.ReadResourceRequest{ - CurrentState: &testTfprotov6DynamicValue, - Private: testBytes, - ProviderMeta: &testTfprotov6DynamicValue, - TypeName: "test_resource", + CurrentState: &testTfprotov6DynamicValue, + Private: testBytes, + ProviderMeta: &testTfprotov6DynamicValue, + TypeName: "test_resource", + CurrentIdentity: &testTfprotov6ResourceIdentityData, }, }, "client-capabilities-deferral-allowed": { in: &tfprotov5.ReadResourceRequest{ - CurrentState: &testTfprotov5DynamicValue, - Private: testBytes, - ProviderMeta: &testTfprotov5DynamicValue, - TypeName: "test_resource", + CurrentState: &testTfprotov5DynamicValue, + Private: testBytes, + ProviderMeta: &testTfprotov5DynamicValue, + TypeName: "test_resource", + CurrentIdentity: &testTfprotov5ResourceIdentityData, ClientCapabilities: &tfprotov5.ReadResourceClientCapabilities{ DeferralAllowed: true, }, }, expected: &tfprotov6.ReadResourceRequest{ - CurrentState: &testTfprotov6DynamicValue, - Private: testBytes, - ProviderMeta: &testTfprotov6DynamicValue, - TypeName: "test_resource", + CurrentState: &testTfprotov6DynamicValue, + Private: testBytes, + ProviderMeta: &testTfprotov6DynamicValue, + TypeName: "test_resource", + CurrentIdentity: &testTfprotov6ResourceIdentityData, ClientCapabilities: &tfprotov6.ReadResourceClientCapabilities{ DeferralAllowed: true, }, @@ -1772,11 +1988,13 @@ func TestReadResourceResponse(t *testing.T) { Diagnostics: testTfprotov5Diagnostics, NewState: &testTfprotov5DynamicValue, Private: testBytes, + NewIdentity: &testTfprotov5ResourceIdentityData, }, expected: &tfprotov6.ReadResourceResponse{ Diagnostics: testTfprotov6Diagnostics, NewState: &testTfprotov6DynamicValue, Private: testBytes, + NewIdentity: &testTfprotov6ResourceIdentityData, }, }, "deferred-reason": { @@ -1784,6 +2002,7 @@ func TestReadResourceResponse(t *testing.T) { Diagnostics: testTfprotov5Diagnostics, NewState: &testTfprotov5DynamicValue, Private: testBytes, + NewIdentity: &testTfprotov5ResourceIdentityData, Deferred: &tfprotov5.Deferred{ Reason: tfprotov5.DeferredReasonResourceConfigUnknown, }, @@ -1792,6 +2011,7 @@ func TestReadResourceResponse(t *testing.T) { Diagnostics: testTfprotov6Diagnostics, NewState: &testTfprotov6DynamicValue, Private: testBytes, + NewIdentity: &testTfprotov6ResourceIdentityData, Deferred: &tfprotov6.Deferred{ Reason: tfprotov6.DeferredReasonResourceConfigUnknown, }, @@ -2116,6 +2336,82 @@ func TestSchemaNestedBlock(t *testing.T) { } } +func TestResourceIdentitySchema(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + in *tfprotov5.ResourceIdentitySchema + expected *tfprotov6.ResourceIdentitySchema + }{ + "nil": { + in: nil, + expected: nil, + }, + "all-valid-fields": { + in: testTfprotov5ResourceIdentitySchema, + expected: testTfprotov6ResourceIdentitySchema, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := tfprotov5tov6.ResourceIdentitySchema(testCase.in) + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestResourceIdentitySchemaAttribute(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + in *tfprotov5.ResourceIdentitySchemaAttribute + expected *tfprotov6.ResourceIdentitySchemaAttribute + }{ + "nil": { + in: nil, + expected: nil, + }, + "all-valid-fields": { + in: &tfprotov5.ResourceIdentitySchemaAttribute{ + Name: "test", + Description: "test description", + Type: tftypes.String, + RequiredForImport: true, + OptionalForImport: true, + }, + expected: &tfprotov6.ResourceIdentitySchemaAttribute{ + Name: "test", + Description: "test description", + Type: tftypes.String, + RequiredForImport: true, + OptionalForImport: true, + }, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := tfprotov5tov6.ResourceIdentitySchemaAttribute(testCase.in) + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + func TestStopProviderRequest(t *testing.T) { t.Parallel() @@ -2251,7 +2547,7 @@ func TestUpgradeResourceStateRequest(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := tfprotov5tov6.UpgradeResourceStateRequest(testCase.in) + got := tfprotov5tov6.UpgradeResourceStateRequest(testCase.in) // TODO: we need this for UpgradeResourceIdentityState() or similarly named if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) @@ -2298,6 +2594,88 @@ func TestUpgradeResourceStateResponse(t *testing.T) { } } +func TestUpgradeResourceIdentityRequest(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + in *tfprotov5.UpgradeResourceIdentityRequest + expected *tfprotov6.UpgradeResourceIdentityRequest + }{ + "nil": { + in: nil, + expected: nil, + }, + "all-valid-fields": { + in: &tfprotov5.UpgradeResourceIdentityRequest{ + RawIdentity: &tfprotov5.RawIdentity{ + JSON: testBytes, + }, + TypeName: "test_resource", + Version: 1, + }, + expected: &tfprotov6.UpgradeResourceIdentityRequest{ + RawIdentity: &tfprotov6.RawIdentity{ + JSON: testBytes, + }, + TypeName: "test_resource", + Version: 1, + }, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := tfprotov5tov6.UpgradeResourceIdentityRequest(testCase.in) + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestUpgradeResourceIdentityResponse(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + in *tfprotov5.UpgradeResourceIdentityResponse + expected *tfprotov6.UpgradeResourceIdentityResponse + }{ + "nil": { + in: nil, + expected: nil, + }, + "all-valid-fields": { + in: &tfprotov5.UpgradeResourceIdentityResponse{ + Diagnostics: testTfprotov5Diagnostics, + UpgradedIdentity: &testTfprotov5ResourceIdentityData, + }, + expected: &tfprotov6.UpgradeResourceIdentityResponse{ + Diagnostics: testTfprotov6Diagnostics, + UpgradedIdentity: &testTfprotov6ResourceIdentityData, + }, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := tfprotov5tov6.UpgradeResourceIdentityResponse(testCase.in) + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + func TestValidateDataResourceConfigRequest(t *testing.T) { t.Parallel() From bcb529bc5f0f58213245e72a190fac21e7dad156 Mon Sep 17 00:00:00 2001 From: Rain Date: Tue, 11 Feb 2025 10:40:10 -0500 Subject: [PATCH 09/25] Updated tf6muxserver to add resource identity --- internal/tf6testserver/tf6testserver.go | 29 +- tf6muxserver/diagnostics.go | 21 + tf6muxserver/mux_server.go | 45 +++ .../mux_server_GetResourceIdentitySchemas.go | 59 +++ ..._server_GetResourceIdentitySchemas_test.go | 369 ++++++++++++++++++ .../mux_server_UpgradeResourceIdentity.go | 54 +++ ...mux_server_UpgradeResourceIdentity_test.go | 88 +++++ 7 files changed, 664 insertions(+), 1 deletion(-) create mode 100644 tf6muxserver/mux_server_GetResourceIdentitySchemas.go create mode 100644 tf6muxserver/mux_server_GetResourceIdentitySchemas_test.go create mode 100644 tf6muxserver/mux_server_UpgradeResourceIdentity.go create mode 100644 tf6muxserver/mux_server_UpgradeResourceIdentity_test.go diff --git a/internal/tf6testserver/tf6testserver.go b/internal/tf6testserver/tf6testserver.go index 3c605f0..1df0e23 100644 --- a/internal/tf6testserver/tf6testserver.go +++ b/internal/tf6testserver/tf6testserver.go @@ -5,7 +5,6 @@ package tf6testserver import ( "context" - "github.com/hashicorp/terraform-plugin-go/tfprotov6" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -32,6 +31,9 @@ type TestServer struct { GetProviderSchemaCalled bool GetProviderSchemaResponse *tfprotov6.GetProviderSchemaResponse + GetResourceIdentitySchemaCalled bool + GetResourceIdentityResponse *tfprotov6.GetResourceIdentitySchemasResponse + ImportResourceStateCalled map[string]bool MoveResourceStateCalled map[string]bool @@ -49,6 +51,8 @@ type TestServer struct { StopProviderCalled bool StopProviderResponse *tfprotov6.StopProviderResponse + UpgradeResourceIdentityCalled map[string]bool + UpgradeResourceStateCalled map[string]bool ValidateDataResourceConfigCalled map[string]bool @@ -136,6 +140,16 @@ func (s *TestServer) GetProviderSchema(_ context.Context, _ *tfprotov6.GetProvid return &tfprotov6.GetProviderSchemaResponse{}, nil } +func (s *TestServer) GetResourceIdentitySchemas(_ context.Context, _ *tfprotov6.GetResourceIdentitySchemasRequest) (*tfprotov6.GetResourceIdentitySchemasResponse, error) { + s.GetResourceIdentitySchemaCalled = true + + if s.GetResourceIdentityResponse != nil { + return s.GetResourceIdentityResponse, nil + } + + return &tfprotov6.GetResourceIdentitySchemasResponse{}, nil +} + func (s *TestServer) ImportResourceState(_ context.Context, req *tfprotov6.ImportResourceStateRequest) (*tfprotov6.ImportResourceStateResponse, error) { if s.ImportResourceStateCalled == nil { s.ImportResourceStateCalled = make(map[string]bool) @@ -209,6 +223,15 @@ func (s *TestServer) StopProvider(_ context.Context, _ *tfprotov6.StopProviderRe return &tfprotov6.StopProviderResponse{}, nil } +func (s *TestServer) UpgradeResourceIdentity(_ context.Context, req *tfprotov6.UpgradeResourceIdentityRequest) (*tfprotov6.UpgradeResourceIdentityResponse, error) { + if s.UpgradeResourceIdentityCalled == nil { + s.UpgradeResourceIdentityCalled = make(map[string]bool) + } + + s.UpgradeResourceIdentityCalled[req.TypeName] = true + return nil, nil +} + func (s *TestServer) UpgradeResourceState(_ context.Context, req *tfprotov6.UpgradeResourceStateRequest) (*tfprotov6.UpgradeResourceStateResponse, error) { if s.UpgradeResourceStateCalled == nil { s.UpgradeResourceStateCalled = make(map[string]bool) @@ -249,3 +272,7 @@ func (s *TestServer) ValidateProviderConfig(_ context.Context, req *tfprotov6.Va s.ValidateProviderConfigCalled = true return s.ValidateProviderConfigResponse, nil } + +func (s *TestServer) ProviderServerWithResourceIdentity() tfprotov6.ProviderServerWithResourceIdentity { + return s +} diff --git a/tf6muxserver/diagnostics.go b/tf6muxserver/diagnostics.go index 9e4bb29..954fde3 100644 --- a/tf6muxserver/diagnostics.go +++ b/tf6muxserver/diagnostics.go @@ -104,3 +104,24 @@ func resourceMissingError(typeName string) *tfprotov6.Diagnostic { "Missing resource type: " + typeName, } } + +func resourceIdentityDuplicateError(typeName string) *tfprotov6.Diagnostic { + return &tfprotov6.Diagnostic{ + Severity: tfprotov6.DiagnosticSeverityError, + Summary: "Invalid Provider Server Combination", + Detail: "The combined provider has multiple implementations of the same resource identity across underlying providers. " + + "Resource identity types must be implemented by only one underlying provider. " + + "This is always an issue in the provider implementation and should be reported to the provider developers.\n\n" + + "Duplicate identity type for resource: " + typeName, + } +} + +func resourceIdentityMissingError(typeName string) *tfprotov6.Diagnostic { + return &tfprotov6.Diagnostic{ + Severity: tfprotov6.DiagnosticSeverityError, + Summary: "Resource Identity Not Implemented", + Detail: "The combined provider does not implement the requested resource identity type. " + + "This is always an issue in the provider implementation and should be reported to the provider developers.\n\n" + + "Missing identity type for resource: " + typeName, + } +} diff --git a/tf6muxserver/mux_server.go b/tf6muxserver/mux_server.go index b83bb56..97e9f38 100644 --- a/tf6muxserver/mux_server.go +++ b/tf6muxserver/mux_server.go @@ -35,6 +35,9 @@ type muxServer struct { // Resource capabilities are cached during GetMetadata/GetProviderSchema resourceCapabilities map[string]*tfprotov6.ServerCapabilities + // Routing for resource identity + resourceIdentity map[string]tfprotov6.ProviderServer + // serverDiscoveryComplete is whether the mux server's underlying server // discovery of resource types has been completed against all servers. // If false during a resource type specific RPC, the mux server needs to @@ -164,6 +167,41 @@ func (s *muxServer) getFunctionServer(ctx context.Context, name string) (tfproto return server, s.serverDiscoveryDiagnostics, nil } +func (s *muxServer) getIdentityResourceServer(ctx context.Context, typeName string) (tfprotov6.ProviderServer, []*tfprotov6.Diagnostic, error) { + s.serverDiscoveryMutex.RLock() + server, ok := s.resourceIdentity[typeName] + discoveryComplete := s.serverDiscoveryComplete + s.serverDiscoveryMutex.RUnlock() + + if discoveryComplete { + if ok { + return server, s.serverDiscoveryDiagnostics, nil + } + + return nil, []*tfprotov6.Diagnostic{ + resourceIdentityMissingError(typeName), + }, nil + } + + err := s.serverDiscovery(ctx) + + if err != nil || diagnosticsHasError(s.serverDiscoveryDiagnostics) { + return nil, s.serverDiscoveryDiagnostics, err + } + + s.serverDiscoveryMutex.RLock() + server, ok = s.resourceIdentity[typeName] + s.serverDiscoveryMutex.RUnlock() + + if !ok { + return nil, []*tfprotov6.Diagnostic{ + resourceIdentityMissingError(typeName), + }, nil + } + + return server, s.serverDiscoveryDiagnostics, nil +} + func (s *muxServer) getResourceServer(ctx context.Context, typeName string) (tfprotov6.ProviderServer, []*tfprotov6.Diagnostic, error) { s.serverDiscoveryMutex.RLock() server, ok := s.resources[typeName] @@ -269,6 +307,9 @@ func (s *muxServer) serverDiscovery(ctx context.Context) error { s.resources[serverResource.TypeName] = server s.resourceCapabilities[serverResource.TypeName] = metadataResp.ServerCapabilities + + // Resource identity is expected to be implemented in the same server as the resource + s.resourceIdentity[serverResource.TypeName] = server } continue @@ -331,6 +372,8 @@ func (s *muxServer) serverDiscovery(ctx context.Context) error { s.resources[typeName] = server s.resourceCapabilities[typeName] = providerSchemaResp.ServerCapabilities + // Resource identity is expected to be implemented in the same server as the resource + s.resourceIdentity[typeName] = server } } @@ -350,11 +393,13 @@ func (s *muxServer) serverDiscovery(ctx context.Context) error { // - Only one provider implements each data source // - Only one provider implements each function // - Only one provider implements each ephemeral resource +// - Only one provider implements each resource identity func NewMuxServer(_ context.Context, servers ...func() tfprotov6.ProviderServer) (*muxServer, error) { result := muxServer{ dataSources: make(map[string]tfprotov6.ProviderServer), ephemeralResources: make(map[string]tfprotov6.ProviderServer), functions: make(map[string]tfprotov6.ProviderServer), + resourceIdentity: make(map[string]tfprotov6.ProviderServer), resources: make(map[string]tfprotov6.ProviderServer), resourceCapabilities: make(map[string]*tfprotov6.ServerCapabilities), servers: make([]tfprotov6.ProviderServer, 0, len(servers)), diff --git a/tf6muxserver/mux_server_GetResourceIdentitySchemas.go b/tf6muxserver/mux_server_GetResourceIdentitySchemas.go new file mode 100644 index 0000000..13a70f2 --- /dev/null +++ b/tf6muxserver/mux_server_GetResourceIdentitySchemas.go @@ -0,0 +1,59 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package tf6muxserver + +import ( + "context" + "fmt" + "github.com/hashicorp/terraform-plugin-go/tfprotov6" + + "github.com/hashicorp/terraform-plugin-mux/internal/logging" +) + +// GetResourceIdentitySchemas merges the schemas returned by the +// tfprotov6.ResourceIdentitySchema associated with muxServer into a single schema. +// Everything must be returned from only one server. +// Schemas must be identical between all servers. +func (s *muxServer) GetResourceIdentitySchemas(ctx context.Context, req *tfprotov6.GetResourceIdentitySchemasRequest) (*tfprotov6.GetResourceIdentitySchemasResponse, error) { + rpc := "GetResourceIdentitySchemas" + ctx = logging.InitContext(ctx) + ctx = logging.RpcContext(ctx, rpc) + + s.serverDiscoveryMutex.Lock() + defer s.serverDiscoveryMutex.Unlock() + + resp := &tfprotov6.GetResourceIdentitySchemasResponse{ + IdentitySchemas: map[string]*tfprotov6.ResourceIdentitySchema{}, + Diagnostics: []*tfprotov6.Diagnostic{}, + } + + for _, server := range s.servers { + ctx := logging.Tfprotov6ProviderServerContext(ctx, server) + logging.MuxTrace(ctx, "calling downstream server") + + // TODO: Remove and call server.GetResourceIdentitySchemas below directly once interface becomes required. + resourceIdentityServer, err := server.(tfprotov6.ProviderServerWithResourceIdentity).GetResourceIdentitySchemas(ctx, req) + + if err != nil { + return resp, fmt.Errorf("error calling GetResourceIdentitySchemas for %T: %w", server, err) + } + + resp.Diagnostics = append(resp.Diagnostics, resourceIdentityServer.Diagnostics...) + + for resourceIdentityType, schema := range resourceIdentityServer.IdentitySchemas { + if _, ok := resp.IdentitySchemas[resourceIdentityType]; ok { + resp.Diagnostics = append(resp.Diagnostics, resourceIdentityDuplicateError(resourceIdentityType)) + + continue + } + + s.resourceIdentity[resourceIdentityType] = server + resp.IdentitySchemas[resourceIdentityType] = schema + } + } + + s.serverDiscoveryComplete = true + + return resp, nil +} diff --git a/tf6muxserver/mux_server_GetResourceIdentitySchemas_test.go b/tf6muxserver/mux_server_GetResourceIdentitySchemas_test.go new file mode 100644 index 0000000..096e1d5 --- /dev/null +++ b/tf6muxserver/mux_server_GetResourceIdentitySchemas_test.go @@ -0,0 +1,369 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package tf6muxserver_test + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-go/tfprotov6" + + "github.com/hashicorp/terraform-plugin-mux/internal/tf6testserver" + "github.com/hashicorp/terraform-plugin-mux/tf6muxserver" +) + +func TestMuxServerGetResourceIdentitySchema(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + servers []func() tfprotov6.ProviderServer + expectedIdentitySchemas map[string]*tfprotov6.ResourceIdentitySchema + expectedDiagnostics []*tfprotov6.Diagnostic + }{ + "combined": { + servers: []func() tfprotov6.ProviderServer{ + (&tf6testserver.TestServer{ + GetResourceIdentityResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ + IdentitySchemas: map[string]*tfprotov6.ResourceIdentitySchema{ + "test_resource_identity_foo": { + Version: 1, + IdentityAttributes: []*tfprotov6.ResourceIdentitySchemaAttribute{ + { + Name: "req", + RequiredForImport: true, + Description: "this one's required", + }, + { + Name: "opt", + OptionalForImport: true, + Description: "this one's optional", + }, + }, + }, + "test_resource_identity_bar": { + Version: 1, + IdentityAttributes: []*tfprotov6.ResourceIdentitySchemaAttribute{ + { + Name: "req", + RequiredForImport: true, + Description: "this one's required", + }, + { + Name: "opt", + OptionalForImport: true, + Description: "this one's optional", + }, + }, + }, + }, + }, + }).ProviderServer, + (&tf6testserver.TestServer{ + GetResourceIdentityResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ + IdentitySchemas: map[string]*tfprotov6.ResourceIdentitySchema{ + "test_resource_identity_foobar": { + Version: 1, + IdentityAttributes: []*tfprotov6.ResourceIdentitySchemaAttribute{ + { + Name: "req", + RequiredForImport: true, + Description: "this one's required", + }, + { + Name: "opt", + OptionalForImport: true, + Description: "this one's optional", + }, + }, + }, + }, + }, + }).ProviderServer, + }, + expectedIdentitySchemas: map[string]*tfprotov6.ResourceIdentitySchema{ + "test_resource_identity_foo": { + Version: 1, + IdentityAttributes: []*tfprotov6.ResourceIdentitySchemaAttribute{ + { + Name: "req", + RequiredForImport: true, + Description: "this one's required", + }, + { + Name: "opt", + OptionalForImport: true, + Description: "this one's optional", + }, + }, + }, + "test_resource_identity_bar": { + Version: 1, + IdentityAttributes: []*tfprotov6.ResourceIdentitySchemaAttribute{ + { + Name: "req", + RequiredForImport: true, + Description: "this one's required", + }, + { + Name: "opt", + OptionalForImport: true, + Description: "this one's optional", + }, + }, + }, + "test_resource_identity_foobar": { + Version: 1, + IdentityAttributes: []*tfprotov6.ResourceIdentitySchemaAttribute{ + { + Name: "req", + RequiredForImport: true, + Description: "this one's required", + }, + { + Name: "opt", + OptionalForImport: true, + Description: "this one's optional", + }, + }, + }, + }, + expectedDiagnostics: []*tfprotov6.Diagnostic{}, + }, + "duplicate-identity-schema-type": { + servers: []func() tfprotov6.ProviderServer{ + (&tf6testserver.TestServer{ + GetResourceIdentityResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ + IdentitySchemas: map[string]*tfprotov6.ResourceIdentitySchema{ + "test_foo": {}, + }, + }, + }).ProviderServer, + (&tf6testserver.TestServer{ + GetResourceIdentityResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ + IdentitySchemas: map[string]*tfprotov6.ResourceIdentitySchema{ + "test_foo": {}, + }, + }, + }).ProviderServer, + }, + expectedIdentitySchemas: map[string]*tfprotov6.ResourceIdentitySchema{ + "test_foo": {}, + }, + expectedDiagnostics: []*tfprotov6.Diagnostic{ + { + Severity: tfprotov6.DiagnosticSeverityError, + Summary: "Invalid Provider Server Combination", + Detail: "The combined provider has multiple implementations of the same resource identity across underlying providers. " + + "Resource identity types must be implemented by only one underlying provider. " + + "This is always an issue in the provider implementation and should be reported to the provider developers.\n\n" + + "Duplicate identity type for resource: test_foo", + }, + }, + }, + "error-once": { + servers: []func() tfprotov6.ProviderServer{ + (&tf6testserver.TestServer{ + GetResourceIdentityResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ + Diagnostics: []*tfprotov6.Diagnostic{ + { + Severity: tfprotov6.DiagnosticSeverityError, + Summary: "test error summary", + Detail: "test error details", + }, + }, + }, + }).ProviderServer, + (&tf6testserver.TestServer{}).ProviderServer, + (&tf6testserver.TestServer{}).ProviderServer, + }, + expectedIdentitySchemas: map[string]*tfprotov6.ResourceIdentitySchema{}, + expectedDiagnostics: []*tfprotov6.Diagnostic{ + { + Severity: tfprotov6.DiagnosticSeverityError, + Summary: "test error summary", + Detail: "test error details", + }, + }, + }, + "error-multiple": { + servers: []func() tfprotov6.ProviderServer{ + (&tf6testserver.TestServer{ + GetResourceIdentityResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ + Diagnostics: []*tfprotov6.Diagnostic{ + { + Severity: tfprotov6.DiagnosticSeverityError, + Summary: "test error summary", + Detail: "test error details", + }, + }, + }, + }).ProviderServer, + (&tf6testserver.TestServer{}).ProviderServer, + (&tf6testserver.TestServer{ + GetResourceIdentityResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ + Diagnostics: []*tfprotov6.Diagnostic{ + { + Severity: tfprotov6.DiagnosticSeverityError, + Summary: "test error summary", + Detail: "test error details", + }, + }, + }, + }).ProviderServer, + }, + expectedIdentitySchemas: map[string]*tfprotov6.ResourceIdentitySchema{}, + expectedDiagnostics: []*tfprotov6.Diagnostic{ + { + Severity: tfprotov6.DiagnosticSeverityError, + Summary: "test error summary", + Detail: "test error details", + }, + { + Severity: tfprotov6.DiagnosticSeverityError, + Summary: "test error summary", + Detail: "test error details", + }, + }, + }, + "warning-once": { + servers: []func() tfprotov6.ProviderServer{ + (&tf6testserver.TestServer{ + GetResourceIdentityResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ + Diagnostics: []*tfprotov6.Diagnostic{ + { + Severity: tfprotov6.DiagnosticSeverityWarning, + Summary: "test warning summary", + Detail: "test warning details", + }, + }, + }, + }).ProviderServer, + (&tf6testserver.TestServer{}).ProviderServer, + (&tf6testserver.TestServer{}).ProviderServer, + }, + expectedIdentitySchemas: map[string]*tfprotov6.ResourceIdentitySchema{}, + expectedDiagnostics: []*tfprotov6.Diagnostic{ + { + Severity: tfprotov6.DiagnosticSeverityWarning, + Summary: "test warning summary", + Detail: "test warning details", + }, + }, + }, + "warning-multiple": { + servers: []func() tfprotov6.ProviderServer{ + (&tf6testserver.TestServer{ + GetResourceIdentityResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ + Diagnostics: []*tfprotov6.Diagnostic{ + { + Severity: tfprotov6.DiagnosticSeverityWarning, + Summary: "test warning summary", + Detail: "test warning details", + }, + }, + }, + }).ProviderServer, + (&tf6testserver.TestServer{}).ProviderServer, + (&tf6testserver.TestServer{ + GetResourceIdentityResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ + Diagnostics: []*tfprotov6.Diagnostic{ + { + Severity: tfprotov6.DiagnosticSeverityWarning, + Summary: "test warning summary", + Detail: "test warning details", + }, + }, + }, + }).ProviderServer, + }, + expectedIdentitySchemas: map[string]*tfprotov6.ResourceIdentitySchema{}, + expectedDiagnostics: []*tfprotov6.Diagnostic{ + { + Severity: tfprotov6.DiagnosticSeverityWarning, + Summary: "test warning summary", + Detail: "test warning details", + }, + { + Severity: tfprotov6.DiagnosticSeverityWarning, + Summary: "test warning summary", + Detail: "test warning details", + }, + }, + }, + "warning-then-error": { + servers: []func() tfprotov6.ProviderServer{ + (&tf6testserver.TestServer{ + GetResourceIdentityResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ + Diagnostics: []*tfprotov6.Diagnostic{ + { + Severity: tfprotov6.DiagnosticSeverityWarning, + Summary: "test warning summary", + Detail: "test warning details", + }, + }, + }, + }).ProviderServer, + (&tf6testserver.TestServer{}).ProviderServer, + (&tf6testserver.TestServer{ + GetResourceIdentityResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ + Diagnostics: []*tfprotov6.Diagnostic{ + { + Severity: tfprotov6.DiagnosticSeverityError, + Summary: "test error summary", + Detail: "test error details", + }, + }, + }, + }).ProviderServer, + }, + expectedDiagnostics: []*tfprotov6.Diagnostic{ + { + Severity: tfprotov6.DiagnosticSeverityWarning, + Summary: "test warning summary", + Detail: "test warning details", + }, + { + Severity: tfprotov6.DiagnosticSeverityError, + Summary: "test error summary", + Detail: "test error details", + }, + }, + expectedIdentitySchemas: map[string]*tfprotov6.ResourceIdentitySchema{}, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + muxServer, err := tf6muxserver.NewMuxServer(context.Background(), testCase.servers...) + + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + + resourceIdentityServer, ok := muxServer.ProviderServer().(tfprotov6.ProviderServerWithResourceIdentity) + if !ok { + t.Fatal("muxServer should implement tfprotov6.ProviderServerWithResourceIdentity") + } + + resp, err := resourceIdentityServer.GetResourceIdentitySchemas(context.Background(), &tfprotov6.GetResourceIdentitySchemasRequest{}) + + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + + if diff := cmp.Diff(resp.Diagnostics, testCase.expectedDiagnostics); diff != "" { + t.Errorf("diagnostics didn't match expectations: %s", diff) + } + + if diff := cmp.Diff(resp.IdentitySchemas, testCase.expectedIdentitySchemas); diff != "" { + t.Errorf("identity schemas didn't match expectations: %s", diff) + } + }) + } +} diff --git a/tf6muxserver/mux_server_UpgradeResourceIdentity.go b/tf6muxserver/mux_server_UpgradeResourceIdentity.go new file mode 100644 index 0000000..f70374d --- /dev/null +++ b/tf6muxserver/mux_server_UpgradeResourceIdentity.go @@ -0,0 +1,54 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package tf6muxserver + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-go/tfprotov6" + "github.com/hashicorp/terraform-plugin-mux/internal/logging" +) + +// UpgradeResourceState calls the UpgradeResourceState method, passing `req`, +// on the provider that returned the resource specified by req.TypeName in its +// schema. +func (s *muxServer) UpgradeResourceIdentity(ctx context.Context, req *tfprotov6.UpgradeResourceIdentityRequest) (*tfprotov6.UpgradeResourceIdentityResponse, error) { + rpc := "UpgradeResourceIdentity" + ctx = logging.InitContext(ctx) + ctx = logging.RpcContext(ctx, rpc) + + server, diags, err := s.getIdentityResourceServer(ctx, req.TypeName) + + if err != nil { + return nil, err + } + + if diagnosticsHasError(diags) { + return &tfprotov6.UpgradeResourceIdentityResponse{ + Diagnostics: diags, + }, nil + } + + // TODO: Remove and call server.UpgradeResourceIdentity below directly once interface becomes required. + resourceIdentityServer, ok := server.(tfprotov6.ProviderServerWithResourceIdentity) + if !ok { + resp := &tfprotov6.UpgradeResourceIdentityResponse{ + Diagnostics: []*tfprotov6.Diagnostic{ + { + Severity: tfprotov6.DiagnosticSeverityError, + Summary: "UpgradeResourceIdentity Not Implemented", + Detail: "A UpgradeResourceIdentity call was received by the provider, however the provider does not implement UpgradeResourceIdentity. " + + "Either upgrade the provider to a version that implements UpgradeResourceIdentity or this is a bug in Terraform that should be reported to the Terraform maintainers.", + }, + }, + } + + return resp, nil + } + + ctx = logging.Tfprotov6ProviderServerContext(ctx, server) + logging.MuxTrace(ctx, "calling downstream server") + + return resourceIdentityServer.UpgradeResourceIdentity(ctx, req) +} diff --git a/tf6muxserver/mux_server_UpgradeResourceIdentity_test.go b/tf6muxserver/mux_server_UpgradeResourceIdentity_test.go new file mode 100644 index 0000000..34d3d75 --- /dev/null +++ b/tf6muxserver/mux_server_UpgradeResourceIdentity_test.go @@ -0,0 +1,88 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package tf6muxserver_test + +import ( + "context" + "testing" + + "github.com/hashicorp/terraform-plugin-go/tfprotov6" + + "github.com/hashicorp/terraform-plugin-mux/internal/tf6testserver" + "github.com/hashicorp/terraform-plugin-mux/tf6muxserver" +) + +func TestMuxServerUpgradeResourceIdentity(t *testing.T) { + t.Parallel() + + ctx := context.Background() + testServer1 := &tf6testserver.TestServer{ + GetResourceIdentityResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ + IdentitySchemas: map[string]*tfprotov6.ResourceIdentitySchema{ + "test_resource_server1": {}, + }, + }, + GetProviderSchemaResponse: &tfprotov6.GetProviderSchemaResponse{ + ResourceSchemas: map[string]*tfprotov6.Schema{ + "test_resource_server1": {}, + }, + }, + } + testServer2 := &tf6testserver.TestServer{ + GetResourceIdentityResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ + IdentitySchemas: map[string]*tfprotov6.ResourceIdentitySchema{ + "test_resource_server2": {}, + }, + }, + GetProviderSchemaResponse: &tfprotov6.GetProviderSchemaResponse{ + ResourceSchemas: map[string]*tfprotov6.Schema{ + "test_resource_server2": {}, + }, + }, + } + + servers := []func() tfprotov6.ProviderServer{testServer1.ProviderServer, testServer2.ProviderServer} + muxServer, err := tf6muxserver.NewMuxServer(ctx, servers...) + + if err != nil { + t.Fatalf("unexpected error setting up factory: %s", err) + } + + resourceIdentityServer, ok := muxServer.ProviderServer().(tfprotov6.ProviderServerWithResourceIdentity) + if !ok { + t.Fatal("muxServer should implement tfprotov6.ProviderServerWithEphemeralResources") + } + + _, err = resourceIdentityServer.UpgradeResourceIdentity(ctx, &tfprotov6.UpgradeResourceIdentityRequest{ + TypeName: "test_resource_server1", + }) + + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + + if !testServer1.UpgradeResourceIdentityCalled["test_resource_server1"] { + t.Errorf("expected test_resource_server1 UpgradeResourceIdentity to be called on server1") + } + + if testServer2.UpgradeResourceIdentityCalled["test_resource_server1"] { + t.Errorf("unexpected test_resource_server1 UpgradeResourceIdentity called on server2") + } + + _, err = resourceIdentityServer.UpgradeResourceIdentity(ctx, &tfprotov6.UpgradeResourceIdentityRequest{ + TypeName: "test_resource_server2", + }) + + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + + if testServer1.UpgradeResourceIdentityCalled["test_resource_server2"] { + t.Errorf("unexpected test_resource_server2 UpgradeResourceIdentity called on server1") + } + + if !testServer2.UpgradeResourceIdentityCalled["test_resource_server2"] { + t.Errorf("expected test_resource_server2 UpgradeResourceIdentity to be called on server2") + } +} From 8cb8168dddaccf6ed6e15d165c3e29de69914697 Mon Sep 17 00:00:00 2001 From: Rain Date: Tue, 11 Feb 2025 11:32:00 -0500 Subject: [PATCH 10/25] Added resource identity to internal/tfprotov6to5 --- internal/tfprotov6tov5/tfprotov6tov5.go | 131 +++++- internal/tfprotov6tov5/tfprotov6tov5_test.go | 452 +++++++++++++++++-- 2 files changed, 537 insertions(+), 46 deletions(-) diff --git a/internal/tfprotov6tov5/tfprotov6tov5.go b/internal/tfprotov6tov5/tfprotov6tov5.go index 5c082bf..6ad7417 100644 --- a/internal/tfprotov6tov5/tfprotov6tov5.go +++ b/internal/tfprotov6tov5/tfprotov6tov5.go @@ -19,12 +19,13 @@ func ApplyResourceChangeRequest(in *tfprotov6.ApplyResourceChangeRequest) *tfpro } return &tfprotov5.ApplyResourceChangeRequest{ - Config: DynamicValue(in.Config), - PlannedPrivate: in.PlannedPrivate, - PlannedState: DynamicValue(in.PlannedState), - PriorState: DynamicValue(in.PriorState), - ProviderMeta: DynamicValue(in.ProviderMeta), - TypeName: in.TypeName, + Config: DynamicValue(in.Config), + PlannedPrivate: in.PlannedPrivate, + PlannedState: DynamicValue(in.PlannedState), + PriorState: DynamicValue(in.PriorState), + ProviderMeta: DynamicValue(in.ProviderMeta), + TypeName: in.TypeName, + PlannedIdentity: ResourceIdentityData(in.PlannedIdentity), } } @@ -38,6 +39,7 @@ func ApplyResourceChangeResponse(in *tfprotov6.ApplyResourceChangeResponse) *tfp NewState: DynamicValue(in.NewState), Private: in.Private, UnsafeToUseLegacyTypeSystem: in.UnsafeToUseLegacyTypeSystem, //nolint:staticcheck + NewIdentity: ResourceIdentityData(in.NewIdentity), } } @@ -177,6 +179,16 @@ func DynamicValue(in *tfprotov6.DynamicValue) *tfprotov5.DynamicValue { } } +func ResourceIdentityData(in *tfprotov6.ResourceIdentityData) *tfprotov5.ResourceIdentityData { + if in == nil { + return nil + } + + return &tfprotov5.ResourceIdentityData{ + IdentityData: DynamicValue(in.IdentityData), + } +} + func EphemeralResourceMetadata(in tfprotov6.EphemeralResourceMetadata) tfprotov5.EphemeralResourceMetadata { return tfprotov5.EphemeralResourceMetadata{ TypeName: in.TypeName, @@ -393,6 +405,31 @@ func GetProviderSchemaResponse(in *tfprotov6.GetProviderSchemaResponse) (*tfprot }, nil } +func GetResourceIdentitySchemasRequest(in *tfprotov6.GetResourceIdentitySchemasRequest) *tfprotov5.GetResourceIdentitySchemasRequest { + if in == nil { + return nil + } + + return &tfprotov5.GetResourceIdentitySchemasRequest{} +} + +func GetResourceIdentitySchemasResponse(in *tfprotov6.GetResourceIdentitySchemasResponse) *tfprotov5.GetResourceIdentitySchemasResponse { + if in == nil { + return nil + } + + identitySchemas := make(map[string]*tfprotov5.ResourceIdentitySchema, len(in.IdentitySchemas)) + + for k, v := range in.IdentitySchemas { + identitySchemas[k] = ResourceIdentitySchema(v) + } + + return &tfprotov5.GetResourceIdentitySchemasResponse{ + Diagnostics: Diagnostics(in.Diagnostics), + IdentitySchemas: identitySchemas, + } +} + func ImportResourceStateRequest(in *tfprotov6.ImportResourceStateRequest) *tfprotov5.ImportResourceStateRequest { if in == nil { return nil @@ -402,6 +439,7 @@ func ImportResourceStateRequest(in *tfprotov6.ImportResourceStateRequest) *tfpro ClientCapabilities: ImportResourceStateClientCapabilities(in.ClientCapabilities), ID: in.ID, TypeName: in.TypeName, + Identity: ResourceIdentityData(in.Identity), } } @@ -446,6 +484,7 @@ func ImportedResources(in []*tfprotov6.ImportedResource) []*tfprotov5.ImportedRe Private: imp.Private, State: DynamicValue(imp.State), TypeName: imp.TypeName, + Identity: ResourceIdentityData(imp.Identity), }) } @@ -464,6 +503,7 @@ func MoveResourceStateRequest(in *tfprotov6.MoveResourceStateRequest) *tfprotov5 SourceState: RawState(in.SourceState), SourceTypeName: in.SourceTypeName, TargetTypeName: in.TargetTypeName, + SourceIdentity: ResourceIdentityData(in.SourceIdentity), } } @@ -473,9 +513,10 @@ func MoveResourceStateResponse(in *tfprotov6.MoveResourceStateResponse) *tfproto } return &tfprotov5.MoveResourceStateResponse{ - Diagnostics: Diagnostics(in.Diagnostics), - TargetPrivate: in.TargetPrivate, - TargetState: DynamicValue(in.TargetState), + Diagnostics: Diagnostics(in.Diagnostics), + TargetPrivate: in.TargetPrivate, + TargetState: DynamicValue(in.TargetState), + TargetIdentity: ResourceIdentityData(in.TargetIdentity), } } @@ -529,6 +570,7 @@ func PlanResourceChangeRequest(in *tfprotov6.PlanResourceChangeRequest) *tfproto ProposedNewState: DynamicValue(in.ProposedNewState), ProviderMeta: DynamicValue(in.ProviderMeta), TypeName: in.TypeName, + PriorIdentity: ResourceIdentityData(in.PriorIdentity), } } @@ -556,6 +598,7 @@ func PlanResourceChangeResponse(in *tfprotov6.PlanResourceChangeResponse) *tfpro PlannedState: DynamicValue(in.PlannedState), RequiresReplace: in.RequiresReplace, UnsafeToUseLegacyTypeSystem: in.UnsafeToUseLegacyTypeSystem, //nolint:staticcheck + PlannedIdentity: ResourceIdentityData(in.PlannedIdentity), } } @@ -591,6 +634,16 @@ func RawState(in *tfprotov6.RawState) *tfprotov5.RawState { } } +func RawIdentity(in *tfprotov6.RawIdentity) *tfprotov5.RawIdentity { + if in == nil { + return nil + } + + return &tfprotov5.RawIdentity{ + JSON: in.JSON, + } +} + func ReadDataSourceRequest(in *tfprotov6.ReadDataSourceRequest) *tfprotov5.ReadDataSourceRequest { if in == nil { return nil @@ -638,6 +691,7 @@ func ReadResourceRequest(in *tfprotov6.ReadResourceRequest) *tfprotov5.ReadResou Private: in.Private, ProviderMeta: DynamicValue(in.ProviderMeta), TypeName: in.TypeName, + CurrentIdentity: ResourceIdentityData(in.CurrentIdentity), } } @@ -663,6 +717,7 @@ func ReadResourceResponse(in *tfprotov6.ReadResourceResponse) *tfprotov5.ReadRes Diagnostics: Diagnostics(in.Diagnostics), NewState: DynamicValue(in.NewState), Private: in.Private, + NewIdentity: ResourceIdentityData(in.NewIdentity), } } @@ -802,6 +857,41 @@ func SchemaNestedBlock(in *tfprotov6.SchemaNestedBlock) (*tfprotov5.SchemaNested }, nil } +func ResourceIdentitySchema(in *tfprotov6.ResourceIdentitySchema) *tfprotov5.ResourceIdentitySchema { + if in == nil { + return nil + } + + var attrs []*tfprotov5.ResourceIdentitySchemaAttribute + + if in.IdentityAttributes != nil { + attrs = make([]*tfprotov5.ResourceIdentitySchemaAttribute, 0, len(in.IdentityAttributes)) + + for _, attr := range in.IdentityAttributes { + attrs = append(attrs, ResourceIdentitySchemaAttribute(attr)) + } + } + + return &tfprotov5.ResourceIdentitySchema{ + Version: in.Version, + IdentityAttributes: attrs, + } +} + +func ResourceIdentitySchemaAttribute(in *tfprotov6.ResourceIdentitySchemaAttribute) *tfprotov5.ResourceIdentitySchemaAttribute { + if in == nil { + return nil + } + + return &tfprotov5.ResourceIdentitySchemaAttribute{ + Name: in.Name, + Type: in.Type, + RequiredForImport: in.RequiredForImport, + OptionalForImport: in.OptionalForImport, + Description: in.Description, + } +} + func ServerCapabilities(in *tfprotov6.ServerCapabilities) *tfprotov5.ServerCapabilities { if in == nil { return nil @@ -880,6 +970,29 @@ func ValidateDataSourceConfigResponse(in *tfprotov6.ValidateDataResourceConfigRe } } +func UpgradeResourceIdentityRequest(in *tfprotov6.UpgradeResourceIdentityRequest) *tfprotov5.UpgradeResourceIdentityRequest { + if in == nil { + return nil + } + + return &tfprotov5.UpgradeResourceIdentityRequest{ + TypeName: in.TypeName, + Version: in.Version, + RawIdentity: RawIdentity(in.RawIdentity), + } +} + +func UpgradeResourceIdentityResponse(in *tfprotov6.UpgradeResourceIdentityResponse) *tfprotov5.UpgradeResourceIdentityResponse { + if in == nil { + return nil + } + + return &tfprotov5.UpgradeResourceIdentityResponse{ + Diagnostics: Diagnostics(in.Diagnostics), + UpgradedIdentity: ResourceIdentityData(in.UpgradedIdentity), + } +} + func ValidateEphemeralResourceConfigRequest(in *tfprotov6.ValidateEphemeralResourceConfigRequest) *tfprotov5.ValidateEphemeralResourceConfigRequest { if in == nil { return nil diff --git a/internal/tfprotov6tov5/tfprotov6tov5_test.go b/internal/tfprotov6tov5/tfprotov6tov5_test.go index 84b0eae..0e3bbd7 100644 --- a/internal/tfprotov6tov5/tfprotov6tov5_test.go +++ b/internal/tfprotov6tov5/tfprotov6tov5_test.go @@ -46,6 +46,9 @@ var ( testTfprotov5DynamicValue tfprotov5.DynamicValue testTfprotov6DynamicValue tfprotov6.DynamicValue + testTfprotov5ResourceIdentityData tfprotov5.ResourceIdentityData + testTfprotov6ResourceIdentityData tfprotov6.ResourceIdentityData + testTfprotov5EphemeralResourceMetadata tfprotov5.EphemeralResourceMetadata = tfprotov5.EphemeralResourceMetadata{ TypeName: "test_ephemeral_resource", } @@ -119,12 +122,53 @@ var ( Version: 1, } + testTfprotov5ResourceIdentitySchema *tfprotov5.ResourceIdentitySchema = &tfprotov5.ResourceIdentitySchema{ + Version: 1, + IdentityAttributes: []*tfprotov5.ResourceIdentitySchemaAttribute{ + { + Name: "req", + Type: tftypes.String, + RequiredForImport: true, + Description: "this one's required", + }, + { + Name: "opt", + Type: tftypes.String, + OptionalForImport: true, + Description: "this one's optional", + }, + }, + } + testTfprotov6ResourceIdentitySchema *tfprotov6.ResourceIdentitySchema = &tfprotov6.ResourceIdentitySchema{ + Version: 1, + IdentityAttributes: []*tfprotov6.ResourceIdentitySchemaAttribute{ + { + Name: "req", + Type: tftypes.String, + RequiredForImport: true, + Description: "this one's required", + }, + { + Name: "opt", + Type: tftypes.String, + OptionalForImport: true, + Description: "this one's optional", + }, + }, + } + testTime time.Time = time.Date(2000, 1, 2, 3, 4, 5, 6, time.UTC) ) func init() { testTfprotov5DynamicValue, _ = tfprotov5.NewDynamicValue(tftypes.String, tftypes.NewValue(tftypes.String, "test")) testTfprotov6DynamicValue, _ = tfprotov6.NewDynamicValue(tftypes.String, tftypes.NewValue(tftypes.String, "test")) + testTfprotov5ResourceIdentityData = tfprotov5.ResourceIdentityData{ + IdentityData: &testTfprotov5DynamicValue, + } + testTfprotov6ResourceIdentityData = tfprotov6.ResourceIdentityData{ + IdentityData: &testTfprotov6DynamicValue, + } } func TestApplyResourceChangeRequest(t *testing.T) { @@ -140,20 +184,22 @@ func TestApplyResourceChangeRequest(t *testing.T) { }, "all-valid-fields": { in: &tfprotov6.ApplyResourceChangeRequest{ - Config: &testTfprotov6DynamicValue, - PlannedPrivate: testBytes, - PlannedState: &testTfprotov6DynamicValue, - PriorState: &testTfprotov6DynamicValue, - ProviderMeta: &testTfprotov6DynamicValue, - TypeName: "test", + Config: &testTfprotov6DynamicValue, + PlannedPrivate: testBytes, + PlannedState: &testTfprotov6DynamicValue, + PriorState: &testTfprotov6DynamicValue, + ProviderMeta: &testTfprotov6DynamicValue, + TypeName: "test", + PlannedIdentity: &testTfprotov6ResourceIdentityData, }, expected: &tfprotov5.ApplyResourceChangeRequest{ - Config: &testTfprotov5DynamicValue, - PlannedPrivate: testBytes, - PlannedState: &testTfprotov5DynamicValue, - PriorState: &testTfprotov5DynamicValue, - ProviderMeta: &testTfprotov5DynamicValue, - TypeName: "test", + Config: &testTfprotov5DynamicValue, + PlannedPrivate: testBytes, + PlannedState: &testTfprotov5DynamicValue, + PriorState: &testTfprotov5DynamicValue, + ProviderMeta: &testTfprotov5DynamicValue, + TypeName: "test", + PlannedIdentity: &testTfprotov5ResourceIdentityData, }, }, } @@ -190,12 +236,14 @@ func TestApplyResourceChangeResponse(t *testing.T) { NewState: &testTfprotov6DynamicValue, Private: testBytes, UnsafeToUseLegacyTypeSystem: true, + NewIdentity: &testTfprotov6ResourceIdentityData, }, expected: &tfprotov5.ApplyResourceChangeResponse{ Diagnostics: testTfprotov5Diagnostics, NewState: &testTfprotov5DynamicValue, Private: testBytes, UnsafeToUseLegacyTypeSystem: true, + NewIdentity: &testTfprotov5ResourceIdentityData, }, }, } @@ -559,6 +607,42 @@ func TestDynamicValue(t *testing.T) { } } +func TestResourceIdentityData(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + in *tfprotov6.ResourceIdentityData + expected *tfprotov5.ResourceIdentityData + }{ + "nil": { + in: nil, + expected: nil, + }, + "all-valid-fields": { + in: &tfprotov6.ResourceIdentityData{ + IdentityData: &testTfprotov6DynamicValue, + }, + expected: &tfprotov5.ResourceIdentityData{ + IdentityData: &testTfprotov5DynamicValue, + }, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := tfprotov6tov5.ResourceIdentityData(testCase.in) + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + func TestFunction(t *testing.T) { t.Parallel() @@ -920,7 +1004,7 @@ func TestGetProviderSchemaRequest(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := tfprotov6tov5.GetProviderSchemaRequest(testCase.in) + got := tfprotov6tov5.GetProviderSchemaRequest(testCase.in) // TODO: we need this for GetResourceIdentitySchemas() (or similarly named) if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) @@ -1132,6 +1216,80 @@ func TestGetProviderSchemaResponse(t *testing.T) { } } +func TestGetResourceIdentitySchemasRequest(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + in *tfprotov6.GetResourceIdentitySchemasRequest + expected *tfprotov5.GetResourceIdentitySchemasRequest + }{ + "nil": { + in: nil, + expected: nil, + }, + "all-valid-fields": { + in: &tfprotov6.GetResourceIdentitySchemasRequest{}, + expected: &tfprotov5.GetResourceIdentitySchemasRequest{}, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := tfprotov6tov5.GetResourceIdentitySchemasRequest(testCase.in) + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestGetResourceIdentitySchemasResponse(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + in *tfprotov6.GetResourceIdentitySchemasResponse + expected *tfprotov5.GetResourceIdentitySchemasResponse + }{ + "nil": { + in: nil, + expected: nil, + }, + "all-valid-fields": { + in: &tfprotov6.GetResourceIdentitySchemasResponse{ + Diagnostics: testTfprotov6Diagnostics, + IdentitySchemas: map[string]*tfprotov6.ResourceIdentitySchema{ + "test_resource": testTfprotov6ResourceIdentitySchema, + }, + }, + expected: &tfprotov5.GetResourceIdentitySchemasResponse{ + Diagnostics: testTfprotov5Diagnostics, + IdentitySchemas: map[string]*tfprotov5.ResourceIdentitySchema{ + "test_resource": testTfprotov5ResourceIdentitySchema, + }, + }, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := tfprotov6tov5.GetResourceIdentitySchemasResponse(testCase.in) + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + func TestImportResourceStateRequest(t *testing.T) { t.Parallel() @@ -1147,10 +1305,12 @@ func TestImportResourceStateRequest(t *testing.T) { in: &tfprotov6.ImportResourceStateRequest{ ID: "test-id", TypeName: "test_resource", + Identity: &testTfprotov6ResourceIdentityData, }, expected: &tfprotov5.ImportResourceStateRequest{ ID: "test-id", TypeName: "test_resource", + Identity: &testTfprotov5ResourceIdentityData, }, }, "client-capabilities-deferral-allowed": { @@ -1205,6 +1365,7 @@ func TestImportResourceStateResponse(t *testing.T) { Private: testBytes, State: &testTfprotov6DynamicValue, TypeName: "test_resource1", + Identity: &testTfprotov6ResourceIdentityData, }, }, }, @@ -1215,6 +1376,7 @@ func TestImportResourceStateResponse(t *testing.T) { Private: testBytes, State: &testTfprotov5DynamicValue, TypeName: "test_resource1", + Identity: &testTfprotov5ResourceIdentityData, }, }, }, @@ -1285,6 +1447,7 @@ func TestImportedResources(t *testing.T) { Private: testBytes, State: &testTfprotov6DynamicValue, TypeName: "test_resource1", + Identity: &testTfprotov6ResourceIdentityData, }, }, expected: []*tfprotov5.ImportedResource{ @@ -1292,6 +1455,7 @@ func TestImportedResources(t *testing.T) { Private: testBytes, State: &testTfprotov5DynamicValue, TypeName: "test_resource1", + Identity: &testTfprotov5ResourceIdentityData, }, }, }, @@ -1360,6 +1524,7 @@ func TestMoveResourceStateRequest(t *testing.T) { }, SourceTypeName: "test_source", TargetTypeName: "test_target", + SourceIdentity: &testTfprotov6ResourceIdentityData, }, expected: &tfprotov5.MoveResourceStateRequest{ SourcePrivate: testBytes, @@ -1370,6 +1535,7 @@ func TestMoveResourceStateRequest(t *testing.T) { }, SourceTypeName: "test_source", TargetTypeName: "test_target", + SourceIdentity: &testTfprotov5ResourceIdentityData, }, }, } @@ -1402,14 +1568,16 @@ func TestMoveResourceStateResponse(t *testing.T) { }, "all-valid-fields": { in: &tfprotov6.MoveResourceStateResponse{ - Diagnostics: testTfprotov6Diagnostics, - TargetPrivate: testBytes, - TargetState: &testTfprotov6DynamicValue, + Diagnostics: testTfprotov6Diagnostics, + TargetPrivate: testBytes, + TargetState: &testTfprotov6DynamicValue, + TargetIdentity: &testTfprotov6ResourceIdentityData, }, expected: &tfprotov5.MoveResourceStateResponse{ - Diagnostics: testTfprotov5Diagnostics, - TargetState: &testTfprotov5DynamicValue, - TargetPrivate: testBytes, + Diagnostics: testTfprotov5Diagnostics, + TargetState: &testTfprotov5DynamicValue, + TargetPrivate: testBytes, + TargetIdentity: &testTfprotov5ResourceIdentityData, }, }, } @@ -1560,6 +1728,7 @@ func TestPlanResourceChangeRequest(t *testing.T) { ProposedNewState: &testTfprotov6DynamicValue, ProviderMeta: &testTfprotov6DynamicValue, TypeName: "test_resource", + PriorIdentity: &testTfprotov6ResourceIdentityData, }, expected: &tfprotov5.PlanResourceChangeRequest{ Config: &testTfprotov5DynamicValue, @@ -1568,6 +1737,7 @@ func TestPlanResourceChangeRequest(t *testing.T) { ProposedNewState: &testTfprotov5DynamicValue, ProviderMeta: &testTfprotov5DynamicValue, TypeName: "test_resource", + PriorIdentity: &testTfprotov5ResourceIdentityData, }, }, "client-capabilities-deferral-allowed": { @@ -1578,6 +1748,7 @@ func TestPlanResourceChangeRequest(t *testing.T) { ProposedNewState: &testTfprotov6DynamicValue, ProviderMeta: &testTfprotov6DynamicValue, TypeName: "test_resource", + PriorIdentity: &testTfprotov6ResourceIdentityData, ClientCapabilities: &tfprotov6.PlanResourceChangeClientCapabilities{ DeferralAllowed: true, }, @@ -1589,6 +1760,7 @@ func TestPlanResourceChangeRequest(t *testing.T) { ProposedNewState: &testTfprotov5DynamicValue, ProviderMeta: &testTfprotov5DynamicValue, TypeName: "test_resource", + PriorIdentity: &testTfprotov5ResourceIdentityData, ClientCapabilities: &tfprotov5.PlanResourceChangeClientCapabilities{ DeferralAllowed: true, }, @@ -1631,6 +1803,7 @@ func TestPlanResourceChangeResponse(t *testing.T) { tftypes.NewAttributePath().WithAttributeName("test"), }, UnsafeToUseLegacyTypeSystem: true, + PlannedIdentity: &testTfprotov6ResourceIdentityData, }, expected: &tfprotov5.PlanResourceChangeResponse{ Diagnostics: testTfprotov5Diagnostics, @@ -1640,6 +1813,7 @@ func TestPlanResourceChangeResponse(t *testing.T) { tftypes.NewAttributePath().WithAttributeName("test"), }, UnsafeToUseLegacyTypeSystem: true, + PlannedIdentity: &testTfprotov5ResourceIdentityData, }, }, "deferred-reason": { @@ -1651,6 +1825,7 @@ func TestPlanResourceChangeResponse(t *testing.T) { tftypes.NewAttributePath().WithAttributeName("test"), }, UnsafeToUseLegacyTypeSystem: true, + PlannedIdentity: &testTfprotov6ResourceIdentityData, Deferred: &tfprotov6.Deferred{ Reason: tfprotov6.DeferredReasonResourceConfigUnknown, }, @@ -1663,6 +1838,7 @@ func TestPlanResourceChangeResponse(t *testing.T) { tftypes.NewAttributePath().WithAttributeName("test"), }, UnsafeToUseLegacyTypeSystem: true, + PlannedIdentity: &testTfprotov5ResourceIdentityData, Deferred: &tfprotov5.Deferred{ Reason: tfprotov5.DeferredReasonResourceConfigUnknown, }, @@ -1788,7 +1964,43 @@ func TestRawState(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := tfprotov6tov5.RawState(testCase.in) + got := tfprotov6tov5.RawState(testCase.in) // TODO: we need this for raw identity + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestRawIdentity(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + in *tfprotov6.RawIdentity + expected *tfprotov5.RawIdentity + }{ + "nil": { + in: nil, + expected: nil, + }, + "all-valid-fields": { + in: &tfprotov6.RawIdentity{ + JSON: testBytes, + }, + expected: &tfprotov5.RawIdentity{ + JSON: testBytes, + }, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := tfprotov6tov5.RawIdentity(testCase.in) if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) @@ -1922,33 +2134,37 @@ func TestReadResourceRequest(t *testing.T) { }, "all-valid-fields": { in: &tfprotov6.ReadResourceRequest{ - CurrentState: &testTfprotov6DynamicValue, - Private: testBytes, - ProviderMeta: &testTfprotov6DynamicValue, - TypeName: "test_resource", + CurrentState: &testTfprotov6DynamicValue, + Private: testBytes, + ProviderMeta: &testTfprotov6DynamicValue, + TypeName: "test_resource", + CurrentIdentity: &testTfprotov6ResourceIdentityData, }, expected: &tfprotov5.ReadResourceRequest{ - CurrentState: &testTfprotov5DynamicValue, - Private: testBytes, - ProviderMeta: &testTfprotov5DynamicValue, - TypeName: "test_resource", + CurrentState: &testTfprotov5DynamicValue, + Private: testBytes, + ProviderMeta: &testTfprotov5DynamicValue, + TypeName: "test_resource", + CurrentIdentity: &testTfprotov5ResourceIdentityData, }, }, "client-capabilities-deferral-allowed": { in: &tfprotov6.ReadResourceRequest{ - CurrentState: &testTfprotov6DynamicValue, - Private: testBytes, - ProviderMeta: &testTfprotov6DynamicValue, - TypeName: "test_resource", + CurrentState: &testTfprotov6DynamicValue, + Private: testBytes, + ProviderMeta: &testTfprotov6DynamicValue, + TypeName: "test_resource", + CurrentIdentity: &testTfprotov6ResourceIdentityData, ClientCapabilities: &tfprotov6.ReadResourceClientCapabilities{ DeferralAllowed: true, }, }, expected: &tfprotov5.ReadResourceRequest{ - CurrentState: &testTfprotov5DynamicValue, - Private: testBytes, - ProviderMeta: &testTfprotov5DynamicValue, - TypeName: "test_resource", + CurrentState: &testTfprotov5DynamicValue, + Private: testBytes, + ProviderMeta: &testTfprotov5DynamicValue, + TypeName: "test_resource", + CurrentIdentity: &testTfprotov5ResourceIdentityData, ClientCapabilities: &tfprotov5.ReadResourceClientCapabilities{ DeferralAllowed: true, }, @@ -1987,11 +2203,13 @@ func TestReadResourceResponse(t *testing.T) { Diagnostics: testTfprotov6Diagnostics, NewState: &testTfprotov6DynamicValue, Private: testBytes, + NewIdentity: &testTfprotov6ResourceIdentityData, }, expected: &tfprotov5.ReadResourceResponse{ Diagnostics: testTfprotov5Diagnostics, NewState: &testTfprotov5DynamicValue, Private: testBytes, + NewIdentity: &testTfprotov5ResourceIdentityData, }, }, "deferred-reason": { @@ -1999,6 +2217,7 @@ func TestReadResourceResponse(t *testing.T) { Diagnostics: testTfprotov6Diagnostics, NewState: &testTfprotov6DynamicValue, Private: testBytes, + NewIdentity: &testTfprotov6ResourceIdentityData, Deferred: &tfprotov6.Deferred{ Reason: tfprotov6.DeferredReasonResourceConfigUnknown, }, @@ -2007,6 +2226,7 @@ func TestReadResourceResponse(t *testing.T) { Diagnostics: testTfprotov5Diagnostics, NewState: &testTfprotov5DynamicValue, Private: testBytes, + NewIdentity: &testTfprotov5ResourceIdentityData, Deferred: &tfprotov5.Deferred{ Reason: tfprotov5.DeferredReasonResourceConfigUnknown, }, @@ -2465,6 +2685,82 @@ func TestSchemaNestedBlock(t *testing.T) { } } +func TestResourceIdentitySchema(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + in *tfprotov6.ResourceIdentitySchema + expected *tfprotov5.ResourceIdentitySchema + }{ + "nil": { + in: nil, + expected: nil, + }, + "all-valid-fields": { + in: testTfprotov6ResourceIdentitySchema, + expected: testTfprotov5ResourceIdentitySchema, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := tfprotov6tov5.ResourceIdentitySchema(testCase.in) + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestResourceIdentitySchemaAttribute(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + in *tfprotov6.ResourceIdentitySchemaAttribute + expected *tfprotov5.ResourceIdentitySchemaAttribute + }{ + "nil": { + in: nil, + expected: nil, + }, + "all-valid-fields": { + in: &tfprotov6.ResourceIdentitySchemaAttribute{ + Name: "test", + Description: "test description", + Type: tftypes.String, + RequiredForImport: true, + OptionalForImport: true, + }, + expected: &tfprotov5.ResourceIdentitySchemaAttribute{ + Name: "test", + Description: "test description", + Type: tftypes.String, + RequiredForImport: true, + OptionalForImport: true, + }, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := tfprotov6tov5.ResourceIdentitySchemaAttribute(testCase.in) + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + func TestStopProviderRequest(t *testing.T) { t.Parallel() @@ -2600,7 +2896,7 @@ func TestUpgradeResourceStateRequest(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := tfprotov6tov5.UpgradeResourceStateRequest(testCase.in) + got := tfprotov6tov5.UpgradeResourceStateRequest(testCase.in) // TODO: we need this for UpgradeResourceIdentityState() or similarly named if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) @@ -2647,6 +2943,88 @@ func TestUpgradeResourceStateResponse(t *testing.T) { } } +func TestUpgradeResourceIdentityRequest(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + in *tfprotov6.UpgradeResourceIdentityRequest + expected *tfprotov5.UpgradeResourceIdentityRequest + }{ + "nil": { + in: nil, + expected: nil, + }, + "all-valid-fields": { + in: &tfprotov6.UpgradeResourceIdentityRequest{ + RawIdentity: &tfprotov6.RawIdentity{ + JSON: testBytes, + }, + TypeName: "test_resource", + Version: 1, + }, + expected: &tfprotov5.UpgradeResourceIdentityRequest{ + RawIdentity: &tfprotov5.RawIdentity{ + JSON: testBytes, + }, + TypeName: "test_resource", + Version: 1, + }, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := tfprotov6tov5.UpgradeResourceIdentityRequest(testCase.in) + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestUpgradeResourceIdentityResponse(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + in *tfprotov6.UpgradeResourceIdentityResponse + expected *tfprotov5.UpgradeResourceIdentityResponse + }{ + "nil": { + in: nil, + expected: nil, + }, + "all-valid-fields": { + in: &tfprotov6.UpgradeResourceIdentityResponse{ + Diagnostics: testTfprotov6Diagnostics, + UpgradedIdentity: &testTfprotov6ResourceIdentityData, + }, + expected: &tfprotov5.UpgradeResourceIdentityResponse{ + Diagnostics: testTfprotov5Diagnostics, + UpgradedIdentity: &testTfprotov5ResourceIdentityData, + }, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := tfprotov6tov5.UpgradeResourceIdentityResponse(testCase.in) + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + func TestValidateDataSourceConfigRequest(t *testing.T) { t.Parallel() From 9c4f00967f8fbc07c6d47c736bc41b919a8362a3 Mon Sep 17 00:00:00 2001 From: Ansgar Mertens Date: Tue, 11 Feb 2025 17:43:18 +0100 Subject: [PATCH 11/25] implement new rpcs for tf5to6server.go for resource identity --- internal/tf5testserver/tf5testserver.go | 10 +- ..._server_GetResourceIdentitySchemas_test.go | 24 ++--- ...mux_server_UpgradeResourceIdentity_test.go | 4 +- tf5to6server/tf5to6server.go | 28 ++++- tf5to6server/tf5to6server_test.go | 100 ++++++++++++++---- 5 files changed, 122 insertions(+), 44 deletions(-) diff --git a/internal/tf5testserver/tf5testserver.go b/internal/tf5testserver/tf5testserver.go index 12a6dee..abef3e0 100644 --- a/internal/tf5testserver/tf5testserver.go +++ b/internal/tf5testserver/tf5testserver.go @@ -32,8 +32,8 @@ type TestServer struct { GetProviderSchemaCalled bool GetProviderSchemaResponse *tfprotov5.GetProviderSchemaResponse - GetResourceIdentitySchemaCalled bool - GetResourceIdentityResponse *tfprotov5.GetResourceIdentitySchemasResponse + GetResourceIdentitySchemasCalled bool + GetResourceIdentitySchemasResponse *tfprotov5.GetResourceIdentitySchemasResponse ImportResourceStateCalled map[string]bool @@ -142,10 +142,10 @@ func (s *TestServer) GetProviderSchema(_ context.Context, _ *tfprotov5.GetProvid } func (s *TestServer) GetResourceIdentitySchemas(_ context.Context, _ *tfprotov5.GetResourceIdentitySchemasRequest) (*tfprotov5.GetResourceIdentitySchemasResponse, error) { - s.GetResourceIdentitySchemaCalled = true + s.GetResourceIdentitySchemasCalled = true - if s.GetResourceIdentityResponse != nil { - return s.GetResourceIdentityResponse, nil + if s.GetResourceIdentitySchemasResponse != nil { + return s.GetResourceIdentitySchemasResponse, nil } return &tfprotov5.GetResourceIdentitySchemasResponse{}, nil diff --git a/tf5muxserver/mux_server_GetResourceIdentitySchemas_test.go b/tf5muxserver/mux_server_GetResourceIdentitySchemas_test.go index 3061b1f..59039d7 100644 --- a/tf5muxserver/mux_server_GetResourceIdentitySchemas_test.go +++ b/tf5muxserver/mux_server_GetResourceIdentitySchemas_test.go @@ -25,7 +25,7 @@ func TestMuxServerGetResourceIdentitySchema(t *testing.T) { "combined": { servers: []func() tfprotov5.ProviderServer{ (&tf5testserver.TestServer{ - GetResourceIdentityResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ + GetResourceIdentitySchemasResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ IdentitySchemas: map[string]*tfprotov5.ResourceIdentitySchema{ "test_resource_identity_foo": { Version: 1, @@ -61,7 +61,7 @@ func TestMuxServerGetResourceIdentitySchema(t *testing.T) { }, }).ProviderServer, (&tf5testserver.TestServer{ - GetResourceIdentityResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ + GetResourceIdentitySchemasResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ IdentitySchemas: map[string]*tfprotov5.ResourceIdentitySchema{ "test_resource_identity_foobar": { Version: 1, @@ -134,14 +134,14 @@ func TestMuxServerGetResourceIdentitySchema(t *testing.T) { "duplicate-identity-schema-type": { servers: []func() tfprotov5.ProviderServer{ (&tf5testserver.TestServer{ - GetResourceIdentityResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ + GetResourceIdentitySchemasResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ IdentitySchemas: map[string]*tfprotov5.ResourceIdentitySchema{ "test_foo": {}, }, }, }).ProviderServer, (&tf5testserver.TestServer{ - GetResourceIdentityResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ + GetResourceIdentitySchemasResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ IdentitySchemas: map[string]*tfprotov5.ResourceIdentitySchema{ "test_foo": {}, }, @@ -165,7 +165,7 @@ func TestMuxServerGetResourceIdentitySchema(t *testing.T) { "error-once": { servers: []func() tfprotov5.ProviderServer{ (&tf5testserver.TestServer{ - GetResourceIdentityResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ + GetResourceIdentitySchemasResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ Diagnostics: []*tfprotov5.Diagnostic{ { Severity: tfprotov5.DiagnosticSeverityError, @@ -190,7 +190,7 @@ func TestMuxServerGetResourceIdentitySchema(t *testing.T) { "error-multiple": { servers: []func() tfprotov5.ProviderServer{ (&tf5testserver.TestServer{ - GetResourceIdentityResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ + GetResourceIdentitySchemasResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ Diagnostics: []*tfprotov5.Diagnostic{ { Severity: tfprotov5.DiagnosticSeverityError, @@ -202,7 +202,7 @@ func TestMuxServerGetResourceIdentitySchema(t *testing.T) { }).ProviderServer, (&tf5testserver.TestServer{}).ProviderServer, (&tf5testserver.TestServer{ - GetResourceIdentityResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ + GetResourceIdentitySchemasResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ Diagnostics: []*tfprotov5.Diagnostic{ { Severity: tfprotov5.DiagnosticSeverityError, @@ -230,7 +230,7 @@ func TestMuxServerGetResourceIdentitySchema(t *testing.T) { "warning-once": { servers: []func() tfprotov5.ProviderServer{ (&tf5testserver.TestServer{ - GetResourceIdentityResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ + GetResourceIdentitySchemasResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ Diagnostics: []*tfprotov5.Diagnostic{ { Severity: tfprotov5.DiagnosticSeverityWarning, @@ -255,7 +255,7 @@ func TestMuxServerGetResourceIdentitySchema(t *testing.T) { "warning-multiple": { servers: []func() tfprotov5.ProviderServer{ (&tf5testserver.TestServer{ - GetResourceIdentityResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ + GetResourceIdentitySchemasResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ Diagnostics: []*tfprotov5.Diagnostic{ { Severity: tfprotov5.DiagnosticSeverityWarning, @@ -267,7 +267,7 @@ func TestMuxServerGetResourceIdentitySchema(t *testing.T) { }).ProviderServer, (&tf5testserver.TestServer{}).ProviderServer, (&tf5testserver.TestServer{ - GetResourceIdentityResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ + GetResourceIdentitySchemasResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ Diagnostics: []*tfprotov5.Diagnostic{ { Severity: tfprotov5.DiagnosticSeverityWarning, @@ -295,7 +295,7 @@ func TestMuxServerGetResourceIdentitySchema(t *testing.T) { "warning-then-error": { servers: []func() tfprotov5.ProviderServer{ (&tf5testserver.TestServer{ - GetResourceIdentityResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ + GetResourceIdentitySchemasResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ Diagnostics: []*tfprotov5.Diagnostic{ { Severity: tfprotov5.DiagnosticSeverityWarning, @@ -307,7 +307,7 @@ func TestMuxServerGetResourceIdentitySchema(t *testing.T) { }).ProviderServer, (&tf5testserver.TestServer{}).ProviderServer, (&tf5testserver.TestServer{ - GetResourceIdentityResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ + GetResourceIdentitySchemasResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ Diagnostics: []*tfprotov5.Diagnostic{ { Severity: tfprotov5.DiagnosticSeverityError, diff --git a/tf5muxserver/mux_server_UpgradeResourceIdentity_test.go b/tf5muxserver/mux_server_UpgradeResourceIdentity_test.go index b338f35..8d1088e 100644 --- a/tf5muxserver/mux_server_UpgradeResourceIdentity_test.go +++ b/tf5muxserver/mux_server_UpgradeResourceIdentity_test.go @@ -18,7 +18,7 @@ func TestMuxServerUpgradeResourceIdentity(t *testing.T) { ctx := context.Background() testServer1 := &tf5testserver.TestServer{ - GetResourceIdentityResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ + GetResourceIdentitySchemasResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ IdentitySchemas: map[string]*tfprotov5.ResourceIdentitySchema{ "test_resource_server1": {}, }, @@ -30,7 +30,7 @@ func TestMuxServerUpgradeResourceIdentity(t *testing.T) { }, } testServer2 := &tf5testserver.TestServer{ - GetResourceIdentityResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ + GetResourceIdentitySchemasResponse: &tfprotov5.GetResourceIdentitySchemasResponse{ IdentitySchemas: map[string]*tfprotov5.ResourceIdentitySchema{ "test_resource_server2": {}, }, diff --git a/tf5to6server/tf5to6server.go b/tf5to6server/tf5to6server.go index 4202f66..06b8c64 100644 --- a/tf5to6server/tf5to6server.go +++ b/tf5to6server/tf5to6server.go @@ -21,16 +21,16 @@ import ( // // Terraform CLI 1.1.5 or later is required for terraform-provider-sdk based // protocol version 5 servers to properly upgrade to protocol version 6. -func UpgradeServer(_ context.Context, v5server func() tfprotov5.ProviderServer) (tfprotov6.ProviderServer, error) { +func UpgradeServer(_ context.Context, v5server func() tfprotov5.ProviderServerWithResourceIdentity) (tfprotov6.ProviderServerWithResourceIdentity, error) { return v5tov6Server{ v5Server: v5server(), }, nil } -var _ tfprotov6.ProviderServer = v5tov6Server{} +var _ tfprotov6.ProviderServerWithResourceIdentity = v5tov6Server{} type v5tov6Server struct { - v5Server tfprotov5.ProviderServer + v5Server tfprotov5.ProviderServerWithResourceIdentity } func (s v5tov6Server) ApplyResourceChange(ctx context.Context, req *tfprotov6.ApplyResourceChangeRequest) (*tfprotov6.ApplyResourceChangeResponse, error) { @@ -110,6 +110,17 @@ func (s v5tov6Server) GetProviderSchema(ctx context.Context, req *tfprotov6.GetP return tfprotov5tov6.GetProviderSchemaResponse(v5Resp), nil } +func (s v5tov6Server) GetResourceIdentitySchemas(ctx context.Context, req *tfprotov6.GetResourceIdentitySchemasRequest) (*tfprotov6.GetResourceIdentitySchemasResponse, error) { + v5Req := tfprotov6tov5.GetResourceIdentitySchemasRequest(req) + v5Resp, err := s.v5Server.GetResourceIdentitySchemas(ctx, v5Req) + + if err != nil { + return nil, err + } + + return tfprotov5tov6.GetResourceIdentitySchemasResponse(v5Resp), nil +} + func (s v5tov6Server) ImportResourceState(ctx context.Context, req *tfprotov6.ImportResourceStateRequest) (*tfprotov6.ImportResourceStateResponse, error) { v5Req := tfprotov6tov5.ImportResourceStateRequest(req) v5Resp, err := s.v5Server.ImportResourceState(ctx, v5Req) @@ -214,6 +225,17 @@ func (s v5tov6Server) UpgradeResourceState(ctx context.Context, req *tfprotov6.U return tfprotov5tov6.UpgradeResourceStateResponse(v5Resp), nil } +func (s v5tov6Server) UpgradeResourceIdentity(ctx context.Context, req *tfprotov6.UpgradeResourceIdentityRequest) (*tfprotov6.UpgradeResourceIdentityResponse, error) { + v5Req := tfprotov6tov5.UpgradeResourceIdentityRequest(req) + v5Resp, err := s.v5Server.UpgradeResourceIdentity(ctx, v5Req) + + if err != nil { + return nil, err + } + + return tfprotov5tov6.UpgradeResourceIdentityResponse(v5Resp), nil +} + func (s v5tov6Server) ValidateDataResourceConfig(ctx context.Context, req *tfprotov6.ValidateDataResourceConfigRequest) (*tfprotov6.ValidateDataResourceConfigResponse, error) { v5Req := tfprotov6tov5.ValidateDataSourceConfigRequest(req) v5Resp, err := s.v5Server.ValidateDataSourceConfig(ctx, v5Req) diff --git a/tf5to6server/tf5to6server_test.go b/tf5to6server/tf5to6server_test.go index d0f32ec..b1c5192 100644 --- a/tf5to6server/tf5to6server_test.go +++ b/tf5to6server/tf5to6server_test.go @@ -20,7 +20,7 @@ func TestUpgradeServer(t *testing.T) { t.Parallel() testCases := map[string]struct { - v5Server func() tfprotov5.ProviderServer + v5Server func() tfprotov5.ProviderServerWithResourceIdentity expectedError error }{ "compatible": { @@ -103,7 +103,7 @@ func TestUpgradeServer(t *testing.T) { "test_resource": {}, }, }, - }).ProviderServer, + }).ProviderServerWithResourceIdentity, }, } @@ -144,7 +144,7 @@ func TestV6ToV5ServerApplyResourceChange(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) if err != nil { t.Fatalf("unexpected error downgrading server: %s", err) @@ -175,7 +175,7 @@ func TestV6ToV5ServerCallFunction(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) if err != nil { t.Fatalf("unexpected error upgrading server: %s", err) @@ -206,7 +206,7 @@ func TestV6ToV5ServerCloseEphemeralResource(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) if err != nil { t.Fatalf("unexpected error downgrading server: %s", err) @@ -237,7 +237,7 @@ func TestV6ToV5ServerConfigureProvider(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) if err != nil { t.Fatalf("unexpected error downgrading server: %s", err) @@ -266,7 +266,7 @@ func TestV6ToV5ServerGetFunctions(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) if err != nil { t.Fatalf("unexpected error upgrading server: %s", err) @@ -297,7 +297,7 @@ func TestV6ToV5ServerGetMetadata(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) if err != nil { t.Fatalf("unexpected error downgrading server: %s", err) @@ -326,7 +326,7 @@ func TestV6ToV5ServerGetProviderSchema(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) if err != nil { t.Fatalf("unexpected error downgrading server: %s", err) @@ -343,6 +343,31 @@ func TestV6ToV5ServerGetProviderSchema(t *testing.T) { } } +func TestV6ToV5ServerGetResourceIdentitySchemas(t *testing.T) { + t.Parallel() + + ctx := context.Background() + v5server := &tf5testserver.TestServer{ + GetResourceIdentitySchemasResponse: &tfprotov5.GetResourceIdentitySchemasResponse{}, + } + + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) + + if err != nil { + t.Fatalf("unexpected error downgrading server: %s", err) + } + + _, err = v6server.GetResourceIdentitySchemas(ctx, &tfprotov6.GetResourceIdentitySchemasRequest{}) + + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + + if !v5server.GetResourceIdentitySchemasCalled { + t.Errorf("expected GetResourceIdentitySchemas to be called") + } +} + func TestV6ToV5ServerImportResourceState(t *testing.T) { t.Parallel() @@ -355,7 +380,7 @@ func TestV6ToV5ServerImportResourceState(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) if err != nil { t.Fatalf("unexpected error downgrading server: %s", err) @@ -386,7 +411,7 @@ func TestV5ToV6ServerMoveResourceState(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) if err != nil { t.Fatalf("unexpected error downgrading server: %s", err) @@ -417,7 +442,7 @@ func TestV6ToV5ServerOpenEphemeralResource(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) if err != nil { t.Fatalf("unexpected error downgrading server: %s", err) @@ -448,7 +473,7 @@ func TestV6ToV5ServerPlanResourceChange(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) if err != nil { t.Fatalf("unexpected error downgrading server: %s", err) @@ -479,7 +504,7 @@ func TestV6ToV5ServerReadDataSource(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) if err != nil { t.Fatalf("unexpected error downgrading server: %s", err) @@ -510,7 +535,7 @@ func TestV6ToV5ServerReadResource(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) if err != nil { t.Fatalf("unexpected error downgrading server: %s", err) @@ -541,7 +566,7 @@ func TestV6ToV5ServerRenewEphemeralResource(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) if err != nil { t.Fatalf("unexpected error downgrading server: %s", err) @@ -572,7 +597,7 @@ func TestV6ToV5ServerStopProvider(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) if err != nil { t.Fatalf("unexpected error downgrading server: %s", err) @@ -601,7 +626,7 @@ func TestV6ToV5ServerUpgradeResourceState(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) if err != nil { t.Fatalf("unexpected error downgrading server: %s", err) @@ -620,6 +645,37 @@ func TestV6ToV5ServerUpgradeResourceState(t *testing.T) { } } +func TestV6ToV5ServerUpgradeResourceIdentity(t *testing.T) { + t.Parallel() + + ctx := context.Background() + v5server := &tf5testserver.TestServer{ + GetProviderSchemaResponse: &tfprotov5.GetProviderSchemaResponse{ + ResourceSchemas: map[string]*tfprotov5.Schema{ + "test_resource": {}, + }, + }, + } + + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) + + if err != nil { + t.Fatalf("unexpected error downgrading server: %s", err) + } + + _, err = v6server.UpgradeResourceIdentity(ctx, &tfprotov6.UpgradeResourceIdentityRequest{ + TypeName: "test_resource", + }) + + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + + if !v5server.UpgradeResourceIdentityCalled["test_resource"] { + t.Errorf("expected test_resource UpgradeResourceState to be called") + } +} + func TestV6ToV5ServerValidateDataResourceConfig(t *testing.T) { t.Parallel() @@ -632,7 +688,7 @@ func TestV6ToV5ServerValidateDataResourceConfig(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) if err != nil { t.Fatalf("unexpected error downgrading server: %s", err) @@ -663,7 +719,7 @@ func TestV6ToV5ServerValidateEphemeralResourceConfig(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) if err != nil { t.Fatalf("unexpected error downgrading server: %s", err) @@ -694,7 +750,7 @@ func TestV6ToV5ServerValidateProviderConfig(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) if err != nil { t.Fatalf("unexpected error downgrading server: %s", err) @@ -723,7 +779,7 @@ func TestV6ToV5ServerValidateResourceConfig(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) if err != nil { t.Fatalf("unexpected error downgrading server: %s", err) From 5d4d1cbf8eb30cbd5dbdbae2e96707faa9c574eb Mon Sep 17 00:00:00 2001 From: Ansgar Mertens Date: Tue, 11 Feb 2025 17:56:53 +0100 Subject: [PATCH 12/25] wip - maybe this works to temp disable lint --- .golangci.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 0396bb9..7c578ab 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,6 +1,10 @@ issues: - max-per-linter: 0 + max-issues-per-linter: 0 max-same-issues: 0 + exclude-rules: + - path: "ProviderServerWithResourceIdentity" + linters: + - SA1019 linters: disable-all: true @@ -22,4 +26,4 @@ linters: - tenv - unconvert - unparam - - unused + - unused \ No newline at end of file From 236a0f636ea830c029b73736668515a96411e2e5 Mon Sep 17 00:00:00 2001 From: Rain Date: Tue, 11 Feb 2025 13:22:06 -0500 Subject: [PATCH 13/25] Added resource identity to internal/tf6to5test server and updated GetResourceIdentityResponse to GetResourceIdentitySchemasResponse --- internal/tf6testserver/tf6testserver.go | 10 +-- ..._server_GetResourceIdentitySchemas_test.go | 24 +++---- ...mux_server_UpgradeResourceIdentity_test.go | 4 +- tf6to5server/tf6to5server.go | 56 ++++++++++++++++ tf6to5server/tf6to5server_test.go | 66 +++++++++++++++++++ 5 files changed, 141 insertions(+), 19 deletions(-) diff --git a/internal/tf6testserver/tf6testserver.go b/internal/tf6testserver/tf6testserver.go index 1df0e23..4be2b44 100644 --- a/internal/tf6testserver/tf6testserver.go +++ b/internal/tf6testserver/tf6testserver.go @@ -31,8 +31,8 @@ type TestServer struct { GetProviderSchemaCalled bool GetProviderSchemaResponse *tfprotov6.GetProviderSchemaResponse - GetResourceIdentitySchemaCalled bool - GetResourceIdentityResponse *tfprotov6.GetResourceIdentitySchemasResponse + GetResourceIdentitySchemasCalled bool + GetResourceIdentitySchemasResponse *tfprotov6.GetResourceIdentitySchemasResponse ImportResourceStateCalled map[string]bool @@ -141,10 +141,10 @@ func (s *TestServer) GetProviderSchema(_ context.Context, _ *tfprotov6.GetProvid } func (s *TestServer) GetResourceIdentitySchemas(_ context.Context, _ *tfprotov6.GetResourceIdentitySchemasRequest) (*tfprotov6.GetResourceIdentitySchemasResponse, error) { - s.GetResourceIdentitySchemaCalled = true + s.GetResourceIdentitySchemasCalled = true - if s.GetResourceIdentityResponse != nil { - return s.GetResourceIdentityResponse, nil + if s.GetResourceIdentitySchemasResponse != nil { + return s.GetResourceIdentitySchemasResponse, nil } return &tfprotov6.GetResourceIdentitySchemasResponse{}, nil diff --git a/tf6muxserver/mux_server_GetResourceIdentitySchemas_test.go b/tf6muxserver/mux_server_GetResourceIdentitySchemas_test.go index 096e1d5..568c0f5 100644 --- a/tf6muxserver/mux_server_GetResourceIdentitySchemas_test.go +++ b/tf6muxserver/mux_server_GetResourceIdentitySchemas_test.go @@ -25,7 +25,7 @@ func TestMuxServerGetResourceIdentitySchema(t *testing.T) { "combined": { servers: []func() tfprotov6.ProviderServer{ (&tf6testserver.TestServer{ - GetResourceIdentityResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ + GetResourceIdentitySchemasResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ IdentitySchemas: map[string]*tfprotov6.ResourceIdentitySchema{ "test_resource_identity_foo": { Version: 1, @@ -61,7 +61,7 @@ func TestMuxServerGetResourceIdentitySchema(t *testing.T) { }, }).ProviderServer, (&tf6testserver.TestServer{ - GetResourceIdentityResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ + GetResourceIdentitySchemasResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ IdentitySchemas: map[string]*tfprotov6.ResourceIdentitySchema{ "test_resource_identity_foobar": { Version: 1, @@ -134,14 +134,14 @@ func TestMuxServerGetResourceIdentitySchema(t *testing.T) { "duplicate-identity-schema-type": { servers: []func() tfprotov6.ProviderServer{ (&tf6testserver.TestServer{ - GetResourceIdentityResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ + GetResourceIdentitySchemasResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ IdentitySchemas: map[string]*tfprotov6.ResourceIdentitySchema{ "test_foo": {}, }, }, }).ProviderServer, (&tf6testserver.TestServer{ - GetResourceIdentityResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ + GetResourceIdentitySchemasResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ IdentitySchemas: map[string]*tfprotov6.ResourceIdentitySchema{ "test_foo": {}, }, @@ -165,7 +165,7 @@ func TestMuxServerGetResourceIdentitySchema(t *testing.T) { "error-once": { servers: []func() tfprotov6.ProviderServer{ (&tf6testserver.TestServer{ - GetResourceIdentityResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ + GetResourceIdentitySchemasResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ Diagnostics: []*tfprotov6.Diagnostic{ { Severity: tfprotov6.DiagnosticSeverityError, @@ -190,7 +190,7 @@ func TestMuxServerGetResourceIdentitySchema(t *testing.T) { "error-multiple": { servers: []func() tfprotov6.ProviderServer{ (&tf6testserver.TestServer{ - GetResourceIdentityResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ + GetResourceIdentitySchemasResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ Diagnostics: []*tfprotov6.Diagnostic{ { Severity: tfprotov6.DiagnosticSeverityError, @@ -202,7 +202,7 @@ func TestMuxServerGetResourceIdentitySchema(t *testing.T) { }).ProviderServer, (&tf6testserver.TestServer{}).ProviderServer, (&tf6testserver.TestServer{ - GetResourceIdentityResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ + GetResourceIdentitySchemasResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ Diagnostics: []*tfprotov6.Diagnostic{ { Severity: tfprotov6.DiagnosticSeverityError, @@ -230,7 +230,7 @@ func TestMuxServerGetResourceIdentitySchema(t *testing.T) { "warning-once": { servers: []func() tfprotov6.ProviderServer{ (&tf6testserver.TestServer{ - GetResourceIdentityResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ + GetResourceIdentitySchemasResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ Diagnostics: []*tfprotov6.Diagnostic{ { Severity: tfprotov6.DiagnosticSeverityWarning, @@ -255,7 +255,7 @@ func TestMuxServerGetResourceIdentitySchema(t *testing.T) { "warning-multiple": { servers: []func() tfprotov6.ProviderServer{ (&tf6testserver.TestServer{ - GetResourceIdentityResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ + GetResourceIdentitySchemasResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ Diagnostics: []*tfprotov6.Diagnostic{ { Severity: tfprotov6.DiagnosticSeverityWarning, @@ -267,7 +267,7 @@ func TestMuxServerGetResourceIdentitySchema(t *testing.T) { }).ProviderServer, (&tf6testserver.TestServer{}).ProviderServer, (&tf6testserver.TestServer{ - GetResourceIdentityResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ + GetResourceIdentitySchemasResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ Diagnostics: []*tfprotov6.Diagnostic{ { Severity: tfprotov6.DiagnosticSeverityWarning, @@ -295,7 +295,7 @@ func TestMuxServerGetResourceIdentitySchema(t *testing.T) { "warning-then-error": { servers: []func() tfprotov6.ProviderServer{ (&tf6testserver.TestServer{ - GetResourceIdentityResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ + GetResourceIdentitySchemasResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ Diagnostics: []*tfprotov6.Diagnostic{ { Severity: tfprotov6.DiagnosticSeverityWarning, @@ -307,7 +307,7 @@ func TestMuxServerGetResourceIdentitySchema(t *testing.T) { }).ProviderServer, (&tf6testserver.TestServer{}).ProviderServer, (&tf6testserver.TestServer{ - GetResourceIdentityResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ + GetResourceIdentitySchemasResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ Diagnostics: []*tfprotov6.Diagnostic{ { Severity: tfprotov6.DiagnosticSeverityError, diff --git a/tf6muxserver/mux_server_UpgradeResourceIdentity_test.go b/tf6muxserver/mux_server_UpgradeResourceIdentity_test.go index 34d3d75..f5d9b62 100644 --- a/tf6muxserver/mux_server_UpgradeResourceIdentity_test.go +++ b/tf6muxserver/mux_server_UpgradeResourceIdentity_test.go @@ -18,7 +18,7 @@ func TestMuxServerUpgradeResourceIdentity(t *testing.T) { ctx := context.Background() testServer1 := &tf6testserver.TestServer{ - GetResourceIdentityResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ + GetResourceIdentitySchemasResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ IdentitySchemas: map[string]*tfprotov6.ResourceIdentitySchema{ "test_resource_server1": {}, }, @@ -30,7 +30,7 @@ func TestMuxServerUpgradeResourceIdentity(t *testing.T) { }, } testServer2 := &tf6testserver.TestServer{ - GetResourceIdentityResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ + GetResourceIdentitySchemasResponse: &tfprotov6.GetResourceIdentitySchemasResponse{ IdentitySchemas: map[string]*tfprotov6.ResourceIdentitySchema{ "test_resource_server2": {}, }, diff --git a/tf6to5server/tf6to5server.go b/tf6to5server/tf6to5server.go index aee6383..779284e 100644 --- a/tf6to5server/tf6to5server.go +++ b/tf6to5server/tf6to5server.go @@ -122,6 +122,34 @@ func (s v6tov5Server) GetProviderSchema(ctx context.Context, req *tfprotov5.GetP return tfprotov6tov5.GetProviderSchemaResponse(v6Resp) } +func (s v6tov5Server) GetResourceIdentitySchemas(ctx context.Context, req *tfprotov5.GetResourceIdentitySchemasRequest) (*tfprotov5.GetResourceIdentitySchemasResponse, error) { + // TODO: Remove and call s.v6Server.GetResourceIdentitySchemas below directly once interface becomes required + resourceIdentityServer, ok := s.v6Server.(tfprotov6.ProviderServerWithResourceIdentity) + if !ok { + v5Resp := &tfprotov5.GetResourceIdentitySchemasResponse{ + Diagnostics: []*tfprotov5.Diagnostic{ + { + Severity: tfprotov5.DiagnosticSeverityError, + Summary: "GetResourceIdentitySchemas Not Implemented", + Detail: "A GetResourceIdentitySchemas call was received by the provider, however the provider does not implement the RPC. " + + "Either upgrade the provider to a version that implements GetResourceIdentitySchemas or this is a bug in Terraform that should be reported to the Terraform maintainers.", + }, + }, + } + + return v5Resp, nil + } + + v6Req := tfprotov5tov6.GetResourceIdentitySchemasRequest(req) + v6Resp, err := resourceIdentityServer.GetResourceIdentitySchemas(ctx, v6Req) + + if err != nil { + return nil, err + } + + return tfprotov6tov5.GetResourceIdentitySchemasResponse(v6Resp), nil +} + func (s v6tov5Server) ImportResourceState(ctx context.Context, req *tfprotov5.ImportResourceStateRequest) (*tfprotov5.ImportResourceStateResponse, error) { v6Req := tfprotov5tov6.ImportResourceStateRequest(req) v6Resp, err := s.v6Server.ImportResourceState(ctx, v6Req) @@ -237,6 +265,34 @@ func (s v6tov5Server) UpgradeResourceState(ctx context.Context, req *tfprotov5.U return tfprotov6tov5.UpgradeResourceStateResponse(v6Resp), nil } +func (s v6tov5Server) UpgradeResourceIdentity(ctx context.Context, req *tfprotov5.UpgradeResourceIdentityRequest) (*tfprotov5.UpgradeResourceIdentityResponse, error) { + // TODO: Remove and call s.v6Server.UpgradeResourceIdentity below directly once interface becomes required + resourceIdentityServer, ok := s.v6Server.(tfprotov6.ProviderServerWithResourceIdentity) + if !ok { + v5Resp := &tfprotov5.UpgradeResourceIdentityResponse{ + Diagnostics: []*tfprotov5.Diagnostic{ + { + Severity: tfprotov5.DiagnosticSeverityError, + Summary: "GetResourceIdentitySchemas Not Implemented", + Detail: "A GetResourceIdentitySchemas call was received by the provider, however the provider does not implement the RPC. " + + "Either upgrade the provider to a version that implements GetResourceIdentitySchemas or this is a bug in Terraform that should be reported to the Terraform maintainers.", + }, + }, + } + + return v5Resp, nil + } + + v6Req := tfprotov5tov6.UpgradeResourceIdentityRequest(req) + v6Resp, err := resourceIdentityServer.UpgradeResourceIdentity(ctx, v6Req) + + if err != nil { + return nil, err + } + + return tfprotov6tov5.UpgradeResourceIdentityResponse(v6Resp), nil +} + func (s v6tov5Server) ValidateDataSourceConfig(ctx context.Context, req *tfprotov5.ValidateDataSourceConfigRequest) (*tfprotov5.ValidateDataSourceConfigResponse, error) { v6Req := tfprotov5tov6.ValidateDataResourceConfigRequest(req) v6Resp, err := s.v6Server.ValidateDataResourceConfig(ctx, v6Req) diff --git a/tf6to5server/tf6to5server_test.go b/tf6to5server/tf6to5server_test.go index 4977d8f..e165107 100644 --- a/tf6to5server/tf6to5server_test.go +++ b/tf6to5server/tf6to5server_test.go @@ -441,6 +441,36 @@ func TestV6ToV5ServerGetProviderSchema(t *testing.T) { } } +func TestV6ToV5ServerGetResourceIdentitySchemas(t *testing.T) { + t.Parallel() + + ctx := context.Background() + v6server := &tf6testserver.TestServer{ + GetResourceIdentitySchemasResponse: &tfprotov6.GetResourceIdentitySchemasResponse{}, + } + + v5server, err := tf6to5server.DowngradeServer(context.Background(), v6server.ProviderServer) + + if err != nil { + t.Fatalf("unexpected error downgrading server: %s", err) + } + + resourceIdentityServer, ok := v5server.(tfprotov5.ProviderServerWithResourceIdentity) + if !ok { + t.Fatal("v5server should implement tfprotov5.ProviderServerWithResourceIdentity") + } + + _, err = resourceIdentityServer.GetResourceIdentitySchemas(ctx, &tfprotov5.GetResourceIdentitySchemasRequest{}) + + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + + if !v6server.GetResourceIdentitySchemasCalled { + t.Errorf("expected GetResourceIdentitySchemas to be called") + } +} + func TestV6ToV5ServerImportResourceState(t *testing.T) { t.Parallel() @@ -747,6 +777,42 @@ func TestV6ToV5ServerUpgradeResourceState(t *testing.T) { } } +func TestV6ToV5ServerUpgradeResourceIdentity(t *testing.T) { + t.Parallel() + + ctx := context.Background() + v6server := &tf6testserver.TestServer{ + GetProviderSchemaResponse: &tfprotov6.GetProviderSchemaResponse{ + ResourceSchemas: map[string]*tfprotov6.Schema{ + "test_resource": {}, + }, + }, + } + + v5server, err := tf6to5server.DowngradeServer(context.Background(), v6server.ProviderServer) + + if err != nil { + t.Fatalf("unexpected error downgrading server: %s", err) + } + + resourceIdentityServer, ok := v5server.(tfprotov5.ProviderServerWithResourceIdentity) + if !ok { + t.Fatal("v5server should implement tfprotov5.ProviderServerWithResourceIdentity") + } + + _, err = resourceIdentityServer.UpgradeResourceIdentity(ctx, &tfprotov5.UpgradeResourceIdentityRequest{ + TypeName: "test_resource", + }) + + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + + if !v6server.UpgradeResourceIdentityCalled["test_resource"] { + t.Errorf("expected test_resource UpgradeResourceState to be called") + } +} + func TestV6ToV5ServerValidateDataSourceConfig(t *testing.T) { t.Parallel() From 4edd21326a4c59dc1c61430732611ddde8045b95 Mon Sep 17 00:00:00 2001 From: Rain Date: Tue, 11 Feb 2025 14:49:44 -0500 Subject: [PATCH 14/25] Updated resource identity in internal/tf5to6test server and added no lint to silence go-linter --- .golangci.yml | 4 -- internal/tf5testserver/tf5testserver.go | 1 + internal/tf6testserver/tf6testserver.go | 1 + .../mux_server_GetResourceIdentitySchemas.go | 1 + ..._server_GetResourceIdentitySchemas_test.go | 1 + .../mux_server_UpgradeResourceIdentity.go | 1 + ...mux_server_UpgradeResourceIdentity_test.go | 1 + tf5to6server/tf5to6server.go | 45 +++++++++++-- tf5to6server/tf5to6server_test.go | 64 +++++++++++-------- .../mux_server_GetResourceIdentitySchemas.go | 1 + ..._server_GetResourceIdentitySchemas_test.go | 1 + .../mux_server_UpgradeResourceIdentity.go | 1 + ...mux_server_UpgradeResourceIdentity_test.go | 1 + tf6to5server/tf6to5server.go | 8 ++- tf6to5server/tf6to5server_test.go | 2 + 15 files changed, 95 insertions(+), 38 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 7c578ab..a1def30 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,10 +1,6 @@ issues: max-issues-per-linter: 0 max-same-issues: 0 - exclude-rules: - - path: "ProviderServerWithResourceIdentity" - linters: - - SA1019 linters: disable-all: true diff --git a/internal/tf5testserver/tf5testserver.go b/internal/tf5testserver/tf5testserver.go index abef3e0..4827f33 100644 --- a/internal/tf5testserver/tf5testserver.go +++ b/internal/tf5testserver/tf5testserver.go @@ -274,6 +274,7 @@ func (s *TestServer) PrepareProviderConfig(_ context.Context, req *tfprotov5.Pre return s.PrepareProviderConfigResponse, nil } +//nolint:staticcheck // Intentionally verifying interface implementation func (s *TestServer) ProviderServerWithResourceIdentity() tfprotov5.ProviderServerWithResourceIdentity { return s } diff --git a/internal/tf6testserver/tf6testserver.go b/internal/tf6testserver/tf6testserver.go index 4be2b44..2eaa0a6 100644 --- a/internal/tf6testserver/tf6testserver.go +++ b/internal/tf6testserver/tf6testserver.go @@ -273,6 +273,7 @@ func (s *TestServer) ValidateProviderConfig(_ context.Context, req *tfprotov6.Va return s.ValidateProviderConfigResponse, nil } +//nolint:staticcheck // Intentionally verifying interface implementation func (s *TestServer) ProviderServerWithResourceIdentity() tfprotov6.ProviderServerWithResourceIdentity { return s } diff --git a/tf5muxserver/mux_server_GetResourceIdentitySchemas.go b/tf5muxserver/mux_server_GetResourceIdentitySchemas.go index 5bc1d0a..5373fbb 100644 --- a/tf5muxserver/mux_server_GetResourceIdentitySchemas.go +++ b/tf5muxserver/mux_server_GetResourceIdentitySchemas.go @@ -33,6 +33,7 @@ func (s *muxServer) GetResourceIdentitySchemas(ctx context.Context, req *tfproto logging.MuxTrace(ctx, "calling downstream server") // TODO: Remove and call server.GetResourceIdentitySchemas below directly once interface becomes required. + //nolint:staticcheck // Intentionally verifying interface implementation resourceIdentityServer, err := server.(tfprotov5.ProviderServerWithResourceIdentity).GetResourceIdentitySchemas(ctx, req) if err != nil { diff --git a/tf5muxserver/mux_server_GetResourceIdentitySchemas_test.go b/tf5muxserver/mux_server_GetResourceIdentitySchemas_test.go index 59039d7..1b154a0 100644 --- a/tf5muxserver/mux_server_GetResourceIdentitySchemas_test.go +++ b/tf5muxserver/mux_server_GetResourceIdentitySchemas_test.go @@ -346,6 +346,7 @@ func TestMuxServerGetResourceIdentitySchema(t *testing.T) { t.Fatalf("unexpected error: %s", err) } + //nolint:staticcheck // Intentionally verifying interface implementation resourceIdentityServer, ok := muxServer.ProviderServer().(tfprotov5.ProviderServerWithResourceIdentity) if !ok { t.Fatal("muxServer should implement tfprotov5.ProviderServerWithResourceIdentity") diff --git a/tf5muxserver/mux_server_UpgradeResourceIdentity.go b/tf5muxserver/mux_server_UpgradeResourceIdentity.go index bed5d85..604ef0a 100644 --- a/tf5muxserver/mux_server_UpgradeResourceIdentity.go +++ b/tf5muxserver/mux_server_UpgradeResourceIdentity.go @@ -31,6 +31,7 @@ func (s *muxServer) UpgradeResourceIdentity(ctx context.Context, req *tfprotov5. } // TODO: Remove and call server.UpgradeResourceIdentity below directly once interface becomes required. + //nolint:staticcheck // Intentionally verifying interface implementation resourceIdentityServer, ok := server.(tfprotov5.ProviderServerWithResourceIdentity) if !ok { resp := &tfprotov5.UpgradeResourceIdentityResponse{ diff --git a/tf5muxserver/mux_server_UpgradeResourceIdentity_test.go b/tf5muxserver/mux_server_UpgradeResourceIdentity_test.go index 8d1088e..f4e9711 100644 --- a/tf5muxserver/mux_server_UpgradeResourceIdentity_test.go +++ b/tf5muxserver/mux_server_UpgradeResourceIdentity_test.go @@ -49,6 +49,7 @@ func TestMuxServerUpgradeResourceIdentity(t *testing.T) { t.Fatalf("unexpected error setting up factory: %s", err) } + //nolint:staticcheck // Intentionally verifying interface implementation resourceIdentityServer, ok := muxServer.ProviderServer().(tfprotov5.ProviderServerWithResourceIdentity) if !ok { t.Fatal("muxServer should implement tfprotov5.ProviderServerWithEphemeralResources") diff --git a/tf5to6server/tf5to6server.go b/tf5to6server/tf5to6server.go index 06b8c64..749a0e3 100644 --- a/tf5to6server/tf5to6server.go +++ b/tf5to6server/tf5to6server.go @@ -21,16 +21,16 @@ import ( // // Terraform CLI 1.1.5 or later is required for terraform-provider-sdk based // protocol version 5 servers to properly upgrade to protocol version 6. -func UpgradeServer(_ context.Context, v5server func() tfprotov5.ProviderServerWithResourceIdentity) (tfprotov6.ProviderServerWithResourceIdentity, error) { +func UpgradeServer(_ context.Context, v5server func() tfprotov5.ProviderServer) (tfprotov6.ProviderServer, error) { return v5tov6Server{ v5Server: v5server(), }, nil } -var _ tfprotov6.ProviderServerWithResourceIdentity = v5tov6Server{} +var _ tfprotov6.ProviderServer = v5tov6Server{} type v5tov6Server struct { - v5Server tfprotov5.ProviderServerWithResourceIdentity + v5Server tfprotov5.ProviderServer } func (s v5tov6Server) ApplyResourceChange(ctx context.Context, req *tfprotov6.ApplyResourceChangeRequest) (*tfprotov6.ApplyResourceChangeResponse, error) { @@ -111,8 +111,26 @@ func (s v5tov6Server) GetProviderSchema(ctx context.Context, req *tfprotov6.GetP } func (s v5tov6Server) GetResourceIdentitySchemas(ctx context.Context, req *tfprotov6.GetResourceIdentitySchemasRequest) (*tfprotov6.GetResourceIdentitySchemasResponse, error) { + // TODO: Remove and call s.v6Server.GetResourceIdentitySchemas below directly once interface becomes required + //nolint:staticcheck // Intentionally verifying interface implementation + resourceIdentityServer, ok := s.v5Server.(tfprotov5.ProviderServerWithResourceIdentity) + if !ok { + v6Resp := &tfprotov6.GetResourceIdentitySchemasResponse{ + Diagnostics: []*tfprotov6.Diagnostic{ + { + Severity: tfprotov6.DiagnosticSeverityError, + Summary: "GetResourceIdentitySchemas Not Implemented", + Detail: "A GetResourceIdentitySchemas call was received by the provider, however the provider does not implement the RPC. " + + "Either upgrade the provider to a version that implements GetResourceIdentitySchemas or this is a bug in Terraform that should be reported to the Terraform maintainers.", + }, + }, + } + + return v6Resp, nil + } + v5Req := tfprotov6tov5.GetResourceIdentitySchemasRequest(req) - v5Resp, err := s.v5Server.GetResourceIdentitySchemas(ctx, v5Req) + v5Resp, err := resourceIdentityServer.GetResourceIdentitySchemas(ctx, v5Req) if err != nil { return nil, err @@ -226,8 +244,25 @@ func (s v5tov6Server) UpgradeResourceState(ctx context.Context, req *tfprotov6.U } func (s v5tov6Server) UpgradeResourceIdentity(ctx context.Context, req *tfprotov6.UpgradeResourceIdentityRequest) (*tfprotov6.UpgradeResourceIdentityResponse, error) { + //nolint:staticcheck // Intentionally verifying interface implementation + resourceIdentityServer, ok := s.v5Server.(tfprotov5.ProviderServerWithResourceIdentity) + if !ok { + v6Resp := &tfprotov6.UpgradeResourceIdentityResponse{ + Diagnostics: []*tfprotov6.Diagnostic{ + { + Severity: tfprotov6.DiagnosticSeverityError, + Summary: "UpgradeResourceIdentity Not Implemented", + Detail: "A UpgradeResourceIdentity call was received by the provider, however the provider does not implement the RPC. " + + "Either upgrade the provider to a version that implements UpgradeResourceIdentity or this is a bug in Terraform that should be reported to the Terraform maintainers.", + }, + }, + } + + return v6Resp, nil + } + v5Req := tfprotov6tov5.UpgradeResourceIdentityRequest(req) - v5Resp, err := s.v5Server.UpgradeResourceIdentity(ctx, v5Req) + v5Resp, err := resourceIdentityServer.UpgradeResourceIdentity(ctx, v5Req) if err != nil { return nil, err diff --git a/tf5to6server/tf5to6server_test.go b/tf5to6server/tf5to6server_test.go index b1c5192..66704d9 100644 --- a/tf5to6server/tf5to6server_test.go +++ b/tf5to6server/tf5to6server_test.go @@ -20,7 +20,7 @@ func TestUpgradeServer(t *testing.T) { t.Parallel() testCases := map[string]struct { - v5Server func() tfprotov5.ProviderServerWithResourceIdentity + v5Server func() tfprotov5.ProviderServer expectedError error }{ "compatible": { @@ -103,7 +103,7 @@ func TestUpgradeServer(t *testing.T) { "test_resource": {}, }, }, - }).ProviderServerWithResourceIdentity, + }).ProviderServer, }, } @@ -144,7 +144,7 @@ func TestV6ToV5ServerApplyResourceChange(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) if err != nil { t.Fatalf("unexpected error downgrading server: %s", err) @@ -175,7 +175,7 @@ func TestV6ToV5ServerCallFunction(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) if err != nil { t.Fatalf("unexpected error upgrading server: %s", err) @@ -206,7 +206,7 @@ func TestV6ToV5ServerCloseEphemeralResource(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) if err != nil { t.Fatalf("unexpected error downgrading server: %s", err) @@ -237,7 +237,7 @@ func TestV6ToV5ServerConfigureProvider(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) if err != nil { t.Fatalf("unexpected error downgrading server: %s", err) @@ -266,7 +266,7 @@ func TestV6ToV5ServerGetFunctions(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) if err != nil { t.Fatalf("unexpected error upgrading server: %s", err) @@ -297,7 +297,7 @@ func TestV6ToV5ServerGetMetadata(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) if err != nil { t.Fatalf("unexpected error downgrading server: %s", err) @@ -326,7 +326,7 @@ func TestV6ToV5ServerGetProviderSchema(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) if err != nil { t.Fatalf("unexpected error downgrading server: %s", err) @@ -351,13 +351,19 @@ func TestV6ToV5ServerGetResourceIdentitySchemas(t *testing.T) { GetResourceIdentitySchemasResponse: &tfprotov5.GetResourceIdentitySchemasResponse{}, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) if err != nil { t.Fatalf("unexpected error downgrading server: %s", err) } - _, err = v6server.GetResourceIdentitySchemas(ctx, &tfprotov6.GetResourceIdentitySchemasRequest{}) + //nolint:staticcheck // Intentionally verifying interface implementation + resourceIdentityServer, ok := v6server.(tfprotov6.ProviderServerWithResourceIdentity) + if !ok { + t.Fatal("v6server should implement tfprotov6.ProviderServerWithResourceIdentity") + } + + _, err = resourceIdentityServer.GetResourceIdentitySchemas(ctx, &tfprotov6.GetResourceIdentitySchemasRequest{}) if err != nil { t.Fatalf("unexpected error: %s", err) @@ -380,7 +386,7 @@ func TestV6ToV5ServerImportResourceState(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) if err != nil { t.Fatalf("unexpected error downgrading server: %s", err) @@ -411,7 +417,7 @@ func TestV5ToV6ServerMoveResourceState(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) if err != nil { t.Fatalf("unexpected error downgrading server: %s", err) @@ -442,7 +448,7 @@ func TestV6ToV5ServerOpenEphemeralResource(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) if err != nil { t.Fatalf("unexpected error downgrading server: %s", err) @@ -473,7 +479,7 @@ func TestV6ToV5ServerPlanResourceChange(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) if err != nil { t.Fatalf("unexpected error downgrading server: %s", err) @@ -504,7 +510,7 @@ func TestV6ToV5ServerReadDataSource(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) if err != nil { t.Fatalf("unexpected error downgrading server: %s", err) @@ -535,7 +541,7 @@ func TestV6ToV5ServerReadResource(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) if err != nil { t.Fatalf("unexpected error downgrading server: %s", err) @@ -566,7 +572,7 @@ func TestV6ToV5ServerRenewEphemeralResource(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) if err != nil { t.Fatalf("unexpected error downgrading server: %s", err) @@ -597,7 +603,7 @@ func TestV6ToV5ServerStopProvider(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) if err != nil { t.Fatalf("unexpected error downgrading server: %s", err) @@ -626,7 +632,7 @@ func TestV6ToV5ServerUpgradeResourceState(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) if err != nil { t.Fatalf("unexpected error downgrading server: %s", err) @@ -657,13 +663,19 @@ func TestV6ToV5ServerUpgradeResourceIdentity(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) if err != nil { t.Fatalf("unexpected error downgrading server: %s", err) } - _, err = v6server.UpgradeResourceIdentity(ctx, &tfprotov6.UpgradeResourceIdentityRequest{ + //nolint:staticcheck // Intentionally verifying interface implementation + resourceIdentityServer, ok := v6server.(tfprotov6.ProviderServerWithResourceIdentity) + if !ok { + t.Fatal("v6server should implement tfprotov6.ProviderServerWithResourceIdentity") + } + + _, err = resourceIdentityServer.UpgradeResourceIdentity(ctx, &tfprotov6.UpgradeResourceIdentityRequest{ TypeName: "test_resource", }) @@ -688,7 +700,7 @@ func TestV6ToV5ServerValidateDataResourceConfig(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) if err != nil { t.Fatalf("unexpected error downgrading server: %s", err) @@ -719,7 +731,7 @@ func TestV6ToV5ServerValidateEphemeralResourceConfig(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) if err != nil { t.Fatalf("unexpected error downgrading server: %s", err) @@ -750,7 +762,7 @@ func TestV6ToV5ServerValidateProviderConfig(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) if err != nil { t.Fatalf("unexpected error downgrading server: %s", err) @@ -779,7 +791,7 @@ func TestV6ToV5ServerValidateResourceConfig(t *testing.T) { }, } - v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServerWithResourceIdentity) + v6server, err := tf5to6server.UpgradeServer(context.Background(), v5server.ProviderServer) if err != nil { t.Fatalf("unexpected error downgrading server: %s", err) diff --git a/tf6muxserver/mux_server_GetResourceIdentitySchemas.go b/tf6muxserver/mux_server_GetResourceIdentitySchemas.go index 13a70f2..8c51180 100644 --- a/tf6muxserver/mux_server_GetResourceIdentitySchemas.go +++ b/tf6muxserver/mux_server_GetResourceIdentitySchemas.go @@ -33,6 +33,7 @@ func (s *muxServer) GetResourceIdentitySchemas(ctx context.Context, req *tfproto logging.MuxTrace(ctx, "calling downstream server") // TODO: Remove and call server.GetResourceIdentitySchemas below directly once interface becomes required. + //nolint:staticcheck // Intentionally verifying interface implementation resourceIdentityServer, err := server.(tfprotov6.ProviderServerWithResourceIdentity).GetResourceIdentitySchemas(ctx, req) if err != nil { diff --git a/tf6muxserver/mux_server_GetResourceIdentitySchemas_test.go b/tf6muxserver/mux_server_GetResourceIdentitySchemas_test.go index 568c0f5..3e1facd 100644 --- a/tf6muxserver/mux_server_GetResourceIdentitySchemas_test.go +++ b/tf6muxserver/mux_server_GetResourceIdentitySchemas_test.go @@ -346,6 +346,7 @@ func TestMuxServerGetResourceIdentitySchema(t *testing.T) { t.Fatalf("unexpected error: %s", err) } + //nolint:staticcheck // Intentionally verifying interface implementation resourceIdentityServer, ok := muxServer.ProviderServer().(tfprotov6.ProviderServerWithResourceIdentity) if !ok { t.Fatal("muxServer should implement tfprotov6.ProviderServerWithResourceIdentity") diff --git a/tf6muxserver/mux_server_UpgradeResourceIdentity.go b/tf6muxserver/mux_server_UpgradeResourceIdentity.go index f70374d..5828c6c 100644 --- a/tf6muxserver/mux_server_UpgradeResourceIdentity.go +++ b/tf6muxserver/mux_server_UpgradeResourceIdentity.go @@ -31,6 +31,7 @@ func (s *muxServer) UpgradeResourceIdentity(ctx context.Context, req *tfprotov6. } // TODO: Remove and call server.UpgradeResourceIdentity below directly once interface becomes required. + //nolint:staticcheck // Intentionally verifying interface implementation resourceIdentityServer, ok := server.(tfprotov6.ProviderServerWithResourceIdentity) if !ok { resp := &tfprotov6.UpgradeResourceIdentityResponse{ diff --git a/tf6muxserver/mux_server_UpgradeResourceIdentity_test.go b/tf6muxserver/mux_server_UpgradeResourceIdentity_test.go index f5d9b62..1732028 100644 --- a/tf6muxserver/mux_server_UpgradeResourceIdentity_test.go +++ b/tf6muxserver/mux_server_UpgradeResourceIdentity_test.go @@ -49,6 +49,7 @@ func TestMuxServerUpgradeResourceIdentity(t *testing.T) { t.Fatalf("unexpected error setting up factory: %s", err) } + //nolint:staticcheck // Intentionally verifying interface implementation resourceIdentityServer, ok := muxServer.ProviderServer().(tfprotov6.ProviderServerWithResourceIdentity) if !ok { t.Fatal("muxServer should implement tfprotov6.ProviderServerWithEphemeralResources") diff --git a/tf6to5server/tf6to5server.go b/tf6to5server/tf6to5server.go index 779284e..55f2bd9 100644 --- a/tf6to5server/tf6to5server.go +++ b/tf6to5server/tf6to5server.go @@ -124,6 +124,7 @@ func (s v6tov5Server) GetProviderSchema(ctx context.Context, req *tfprotov5.GetP func (s v6tov5Server) GetResourceIdentitySchemas(ctx context.Context, req *tfprotov5.GetResourceIdentitySchemasRequest) (*tfprotov5.GetResourceIdentitySchemasResponse, error) { // TODO: Remove and call s.v6Server.GetResourceIdentitySchemas below directly once interface becomes required + //nolint:staticcheck // Intentionally verifying interface implementation resourceIdentityServer, ok := s.v6Server.(tfprotov6.ProviderServerWithResourceIdentity) if !ok { v5Resp := &tfprotov5.GetResourceIdentitySchemasResponse{ @@ -267,15 +268,16 @@ func (s v6tov5Server) UpgradeResourceState(ctx context.Context, req *tfprotov5.U func (s v6tov5Server) UpgradeResourceIdentity(ctx context.Context, req *tfprotov5.UpgradeResourceIdentityRequest) (*tfprotov5.UpgradeResourceIdentityResponse, error) { // TODO: Remove and call s.v6Server.UpgradeResourceIdentity below directly once interface becomes required + //nolint:staticcheck // Intentionally verifying interface implementation resourceIdentityServer, ok := s.v6Server.(tfprotov6.ProviderServerWithResourceIdentity) if !ok { v5Resp := &tfprotov5.UpgradeResourceIdentityResponse{ Diagnostics: []*tfprotov5.Diagnostic{ { Severity: tfprotov5.DiagnosticSeverityError, - Summary: "GetResourceIdentitySchemas Not Implemented", - Detail: "A GetResourceIdentitySchemas call was received by the provider, however the provider does not implement the RPC. " + - "Either upgrade the provider to a version that implements GetResourceIdentitySchemas or this is a bug in Terraform that should be reported to the Terraform maintainers.", + Summary: "UpgradeResourceIdentity Not Implemented", + Detail: "A UpgradeResourceIdentity call was received by the provider, however the provider does not implement the RPC. " + + "Either upgrade the provider to a version that implements UpgradeResourceIdentity or this is a bug in Terraform that should be reported to the Terraform maintainers.", }, }, } diff --git a/tf6to5server/tf6to5server_test.go b/tf6to5server/tf6to5server_test.go index e165107..7d0f172 100644 --- a/tf6to5server/tf6to5server_test.go +++ b/tf6to5server/tf6to5server_test.go @@ -455,6 +455,7 @@ func TestV6ToV5ServerGetResourceIdentitySchemas(t *testing.T) { t.Fatalf("unexpected error downgrading server: %s", err) } + //nolint:staticcheck // Intentionally verifying interface implementation resourceIdentityServer, ok := v5server.(tfprotov5.ProviderServerWithResourceIdentity) if !ok { t.Fatal("v5server should implement tfprotov5.ProviderServerWithResourceIdentity") @@ -795,6 +796,7 @@ func TestV6ToV5ServerUpgradeResourceIdentity(t *testing.T) { t.Fatalf("unexpected error downgrading server: %s", err) } + //nolint:staticcheck // Intentionally verifying interface implementation resourceIdentityServer, ok := v5server.(tfprotov5.ProviderServerWithResourceIdentity) if !ok { t.Fatal("v5server should implement tfprotov5.ProviderServerWithResourceIdentity") From 1d6c7d9e3559216daab36dfff3a0815dac789ffe Mon Sep 17 00:00:00 2001 From: Ansgar Mertens Date: Thu, 13 Feb 2025 11:06:33 +0100 Subject: [PATCH 15/25] remove obsolete todo comments (they were all already addressed) --- internal/tfprotov5tov6/tfprotov5tov6_test.go | 6 +++--- internal/tfprotov6tov5/tfprotov6tov5_test.go | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/internal/tfprotov5tov6/tfprotov5tov6_test.go b/internal/tfprotov5tov6/tfprotov5tov6_test.go index 9bfd035..9370e3b 100644 --- a/internal/tfprotov5tov6/tfprotov5tov6_test.go +++ b/internal/tfprotov5tov6/tfprotov5tov6_test.go @@ -1002,7 +1002,7 @@ func TestGetProviderSchemaRequest(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := tfprotov5tov6.GetProviderSchemaRequest(testCase.in) // TODO: we need this for GetResourceIdentitySchemas() (or similarly named) + got := tfprotov5tov6.GetProviderSchemaRequest(testCase.in) if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) @@ -1749,7 +1749,7 @@ func TestRawState(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := tfprotov5tov6.RawState(testCase.in) // TODO: we need this for raw identity + got := tfprotov5tov6.RawState(testCase.in) if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) @@ -2547,7 +2547,7 @@ func TestUpgradeResourceStateRequest(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := tfprotov5tov6.UpgradeResourceStateRequest(testCase.in) // TODO: we need this for UpgradeResourceIdentityState() or similarly named + got := tfprotov5tov6.UpgradeResourceStateRequest(testCase.in) if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) diff --git a/internal/tfprotov6tov5/tfprotov6tov5_test.go b/internal/tfprotov6tov5/tfprotov6tov5_test.go index 0e3bbd7..977f202 100644 --- a/internal/tfprotov6tov5/tfprotov6tov5_test.go +++ b/internal/tfprotov6tov5/tfprotov6tov5_test.go @@ -1004,7 +1004,7 @@ func TestGetProviderSchemaRequest(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := tfprotov6tov5.GetProviderSchemaRequest(testCase.in) // TODO: we need this for GetResourceIdentitySchemas() (or similarly named) + got := tfprotov6tov5.GetProviderSchemaRequest(testCase.in) if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) @@ -1964,7 +1964,7 @@ func TestRawState(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := tfprotov6tov5.RawState(testCase.in) // TODO: we need this for raw identity + got := tfprotov6tov5.RawState(testCase.in) if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) @@ -2896,7 +2896,7 @@ func TestUpgradeResourceStateRequest(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := tfprotov6tov5.UpgradeResourceStateRequest(testCase.in) // TODO: we need this for UpgradeResourceIdentityState() or similarly named + got := tfprotov6tov5.UpgradeResourceStateRequest(testCase.in) if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) From 709401dec641f1de223a8aefa43603341746dd0e Mon Sep 17 00:00:00 2001 From: Ansgar Mertens Date: Thu, 13 Feb 2025 11:11:20 +0100 Subject: [PATCH 16/25] remove resourceIdentity map as we already expect resource and resource identity to be implemented by the same server, so we'll always follow resources --- tf5muxserver/mux_server.go | 44 ------------------- .../mux_server_GetResourceIdentitySchemas.go | 2 +- .../mux_server_UpgradeResourceIdentity.go | 2 +- tf6muxserver/mux_server.go | 44 ------------------- .../mux_server_GetResourceIdentitySchemas.go | 1 - .../mux_server_UpgradeResourceIdentity.go | 2 +- 6 files changed, 3 insertions(+), 92 deletions(-) diff --git a/tf5muxserver/mux_server.go b/tf5muxserver/mux_server.go index ae546b3..1253bd9 100644 --- a/tf5muxserver/mux_server.go +++ b/tf5muxserver/mux_server.go @@ -35,9 +35,6 @@ type muxServer struct { // Resource capabilities are cached during GetMetadata/GetProviderSchema resourceCapabilities map[string]*tfprotov5.ServerCapabilities - // Routing for resource identity - resourceIdentity map[string]tfprotov5.ProviderServer - // serverDiscoveryComplete is whether the mux server's underlying server // discovery of resource types has been completed against all servers. // If false during a resource type specific RPC, the mux server needs to @@ -167,41 +164,6 @@ func (s *muxServer) getFunctionServer(ctx context.Context, name string) (tfproto return server, s.serverDiscoveryDiagnostics, nil } -func (s *muxServer) getIdentityResourceServer(ctx context.Context, typeName string) (tfprotov5.ProviderServer, []*tfprotov5.Diagnostic, error) { - s.serverDiscoveryMutex.RLock() - server, ok := s.resourceIdentity[typeName] - discoveryComplete := s.serverDiscoveryComplete - s.serverDiscoveryMutex.RUnlock() - - if discoveryComplete { - if ok { - return server, s.serverDiscoveryDiagnostics, nil - } - - return nil, []*tfprotov5.Diagnostic{ - resourceIdentityMissingError(typeName), - }, nil - } - - err := s.serverDiscovery(ctx) - - if err != nil || diagnosticsHasError(s.serverDiscoveryDiagnostics) { - return nil, s.serverDiscoveryDiagnostics, err - } - - s.serverDiscoveryMutex.RLock() - server, ok = s.resourceIdentity[typeName] - s.serverDiscoveryMutex.RUnlock() - - if !ok { - return nil, []*tfprotov5.Diagnostic{ - resourceIdentityMissingError(typeName), - }, nil - } - - return server, s.serverDiscoveryDiagnostics, nil -} - func (s *muxServer) getResourceServer(ctx context.Context, typeName string) (tfprotov5.ProviderServer, []*tfprotov5.Diagnostic, error) { s.serverDiscoveryMutex.RLock() server, ok := s.resources[typeName] @@ -307,9 +269,6 @@ func (s *muxServer) serverDiscovery(ctx context.Context) error { s.resources[serverResource.TypeName] = server s.resourceCapabilities[serverResource.TypeName] = metadataResp.ServerCapabilities - - // Resource identity is expected to be implemented in the same server as the resource - s.resourceIdentity[serverResource.TypeName] = server } continue @@ -372,8 +331,6 @@ func (s *muxServer) serverDiscovery(ctx context.Context) error { s.resources[typeName] = server s.resourceCapabilities[typeName] = providerSchemaResp.ServerCapabilities - // Resource identity is expected to be implemented in the same server as the resource - s.resourceIdentity[typeName] = server } } @@ -398,7 +355,6 @@ func NewMuxServer(_ context.Context, servers ...func() tfprotov5.ProviderServer) dataSources: make(map[string]tfprotov5.ProviderServer), ephemeralResources: make(map[string]tfprotov5.ProviderServer), functions: make(map[string]tfprotov5.ProviderServer), - resourceIdentity: make(map[string]tfprotov5.ProviderServer), resources: make(map[string]tfprotov5.ProviderServer), resourceCapabilities: make(map[string]*tfprotov5.ServerCapabilities), } diff --git a/tf5muxserver/mux_server_GetResourceIdentitySchemas.go b/tf5muxserver/mux_server_GetResourceIdentitySchemas.go index 5373fbb..68a762d 100644 --- a/tf5muxserver/mux_server_GetResourceIdentitySchemas.go +++ b/tf5muxserver/mux_server_GetResourceIdentitySchemas.go @@ -6,6 +6,7 @@ package tf5muxserver import ( "context" "fmt" + "github.com/hashicorp/terraform-plugin-go/tfprotov5" "github.com/hashicorp/terraform-plugin-mux/internal/logging" @@ -49,7 +50,6 @@ func (s *muxServer) GetResourceIdentitySchemas(ctx context.Context, req *tfproto continue } - s.resourceIdentity[resourceIdentityType] = server resp.IdentitySchemas[resourceIdentityType] = schema } } diff --git a/tf5muxserver/mux_server_UpgradeResourceIdentity.go b/tf5muxserver/mux_server_UpgradeResourceIdentity.go index 604ef0a..0ddca12 100644 --- a/tf5muxserver/mux_server_UpgradeResourceIdentity.go +++ b/tf5muxserver/mux_server_UpgradeResourceIdentity.go @@ -18,7 +18,7 @@ func (s *muxServer) UpgradeResourceIdentity(ctx context.Context, req *tfprotov5. ctx = logging.InitContext(ctx) ctx = logging.RpcContext(ctx, rpc) - server, diags, err := s.getIdentityResourceServer(ctx, req.TypeName) + server, diags, err := s.getResourceServer(ctx, req.TypeName) if err != nil { return nil, err diff --git a/tf6muxserver/mux_server.go b/tf6muxserver/mux_server.go index 97e9f38..9ca8db5 100644 --- a/tf6muxserver/mux_server.go +++ b/tf6muxserver/mux_server.go @@ -35,9 +35,6 @@ type muxServer struct { // Resource capabilities are cached during GetMetadata/GetProviderSchema resourceCapabilities map[string]*tfprotov6.ServerCapabilities - // Routing for resource identity - resourceIdentity map[string]tfprotov6.ProviderServer - // serverDiscoveryComplete is whether the mux server's underlying server // discovery of resource types has been completed against all servers. // If false during a resource type specific RPC, the mux server needs to @@ -167,41 +164,6 @@ func (s *muxServer) getFunctionServer(ctx context.Context, name string) (tfproto return server, s.serverDiscoveryDiagnostics, nil } -func (s *muxServer) getIdentityResourceServer(ctx context.Context, typeName string) (tfprotov6.ProviderServer, []*tfprotov6.Diagnostic, error) { - s.serverDiscoveryMutex.RLock() - server, ok := s.resourceIdentity[typeName] - discoveryComplete := s.serverDiscoveryComplete - s.serverDiscoveryMutex.RUnlock() - - if discoveryComplete { - if ok { - return server, s.serverDiscoveryDiagnostics, nil - } - - return nil, []*tfprotov6.Diagnostic{ - resourceIdentityMissingError(typeName), - }, nil - } - - err := s.serverDiscovery(ctx) - - if err != nil || diagnosticsHasError(s.serverDiscoveryDiagnostics) { - return nil, s.serverDiscoveryDiagnostics, err - } - - s.serverDiscoveryMutex.RLock() - server, ok = s.resourceIdentity[typeName] - s.serverDiscoveryMutex.RUnlock() - - if !ok { - return nil, []*tfprotov6.Diagnostic{ - resourceIdentityMissingError(typeName), - }, nil - } - - return server, s.serverDiscoveryDiagnostics, nil -} - func (s *muxServer) getResourceServer(ctx context.Context, typeName string) (tfprotov6.ProviderServer, []*tfprotov6.Diagnostic, error) { s.serverDiscoveryMutex.RLock() server, ok := s.resources[typeName] @@ -307,9 +269,6 @@ func (s *muxServer) serverDiscovery(ctx context.Context) error { s.resources[serverResource.TypeName] = server s.resourceCapabilities[serverResource.TypeName] = metadataResp.ServerCapabilities - - // Resource identity is expected to be implemented in the same server as the resource - s.resourceIdentity[serverResource.TypeName] = server } continue @@ -372,8 +331,6 @@ func (s *muxServer) serverDiscovery(ctx context.Context) error { s.resources[typeName] = server s.resourceCapabilities[typeName] = providerSchemaResp.ServerCapabilities - // Resource identity is expected to be implemented in the same server as the resource - s.resourceIdentity[typeName] = server } } @@ -399,7 +356,6 @@ func NewMuxServer(_ context.Context, servers ...func() tfprotov6.ProviderServer) dataSources: make(map[string]tfprotov6.ProviderServer), ephemeralResources: make(map[string]tfprotov6.ProviderServer), functions: make(map[string]tfprotov6.ProviderServer), - resourceIdentity: make(map[string]tfprotov6.ProviderServer), resources: make(map[string]tfprotov6.ProviderServer), resourceCapabilities: make(map[string]*tfprotov6.ServerCapabilities), servers: make([]tfprotov6.ProviderServer, 0, len(servers)), diff --git a/tf6muxserver/mux_server_GetResourceIdentitySchemas.go b/tf6muxserver/mux_server_GetResourceIdentitySchemas.go index 8c51180..533380a 100644 --- a/tf6muxserver/mux_server_GetResourceIdentitySchemas.go +++ b/tf6muxserver/mux_server_GetResourceIdentitySchemas.go @@ -49,7 +49,6 @@ func (s *muxServer) GetResourceIdentitySchemas(ctx context.Context, req *tfproto continue } - s.resourceIdentity[resourceIdentityType] = server resp.IdentitySchemas[resourceIdentityType] = schema } } diff --git a/tf6muxserver/mux_server_UpgradeResourceIdentity.go b/tf6muxserver/mux_server_UpgradeResourceIdentity.go index 5828c6c..4d1267a 100644 --- a/tf6muxserver/mux_server_UpgradeResourceIdentity.go +++ b/tf6muxserver/mux_server_UpgradeResourceIdentity.go @@ -18,7 +18,7 @@ func (s *muxServer) UpgradeResourceIdentity(ctx context.Context, req *tfprotov6. ctx = logging.InitContext(ctx) ctx = logging.RpcContext(ctx, rpc) - server, diags, err := s.getIdentityResourceServer(ctx, req.TypeName) + server, diags, err := s.getResourceServer(ctx, req.TypeName) if err != nil { return nil, err From 3f2383e1f628dc901a27957c3e4bd8b3305a4cfc Mon Sep 17 00:00:00 2001 From: Ansgar Mertens Date: Thu, 13 Feb 2025 11:19:40 +0100 Subject: [PATCH 17/25] safely skip server if it does not implement ProviderServerWithResourceIdentity --- .../mux_server_GetResourceIdentitySchemas.go | 19 +++++++++++++++--- .../mux_server_GetResourceIdentitySchemas.go | 20 ++++++++++++++++--- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/tf5muxserver/mux_server_GetResourceIdentitySchemas.go b/tf5muxserver/mux_server_GetResourceIdentitySchemas.go index 68a762d..77a1cd8 100644 --- a/tf5muxserver/mux_server_GetResourceIdentitySchemas.go +++ b/tf5muxserver/mux_server_GetResourceIdentitySchemas.go @@ -35,15 +35,28 @@ func (s *muxServer) GetResourceIdentitySchemas(ctx context.Context, req *tfproto // TODO: Remove and call server.GetResourceIdentitySchemas below directly once interface becomes required. //nolint:staticcheck // Intentionally verifying interface implementation - resourceIdentityServer, err := server.(tfprotov5.ProviderServerWithResourceIdentity).GetResourceIdentitySchemas(ctx, req) + resourceIdentityServer, ok := server.(tfprotov5.ProviderServerWithResourceIdentity) + + if !ok { + resp.Diagnostics = append(resp.Diagnostics, &tfprotov5.Diagnostic{ + Severity: tfprotov5.DiagnosticSeverityError, + Summary: "GetResourceIdentitySchemas Not Implemented", + Detail: "A GetResourceIdentitySchemas call was received by the provider, however the provider does not implement GetResourceIdentitySchemas. " + + "Either upgrade the provider to a version that implements GetResourceIdentitySchemas or this is a bug in Terraform that should be reported to the Terraform maintainers.", + }) + + continue + } + + resourceIdentitySchemas, err := resourceIdentityServer.GetResourceIdentitySchemas(ctx, req) if err != nil { return resp, fmt.Errorf("error calling GetResourceIdentitySchemas for %T: %w", server, err) } - resp.Diagnostics = append(resp.Diagnostics, resourceIdentityServer.Diagnostics...) + resp.Diagnostics = append(resp.Diagnostics, resourceIdentitySchemas.Diagnostics...) - for resourceIdentityType, schema := range resourceIdentityServer.IdentitySchemas { + for resourceIdentityType, schema := range resourceIdentitySchemas.IdentitySchemas { if _, ok := resp.IdentitySchemas[resourceIdentityType]; ok { resp.Diagnostics = append(resp.Diagnostics, resourceIdentityDuplicateError(resourceIdentityType)) diff --git a/tf6muxserver/mux_server_GetResourceIdentitySchemas.go b/tf6muxserver/mux_server_GetResourceIdentitySchemas.go index 533380a..5b72f07 100644 --- a/tf6muxserver/mux_server_GetResourceIdentitySchemas.go +++ b/tf6muxserver/mux_server_GetResourceIdentitySchemas.go @@ -6,6 +6,7 @@ package tf6muxserver import ( "context" "fmt" + "github.com/hashicorp/terraform-plugin-go/tfprotov6" "github.com/hashicorp/terraform-plugin-mux/internal/logging" @@ -34,15 +35,28 @@ func (s *muxServer) GetResourceIdentitySchemas(ctx context.Context, req *tfproto // TODO: Remove and call server.GetResourceIdentitySchemas below directly once interface becomes required. //nolint:staticcheck // Intentionally verifying interface implementation - resourceIdentityServer, err := server.(tfprotov6.ProviderServerWithResourceIdentity).GetResourceIdentitySchemas(ctx, req) + resourceIdentityServer, ok := server.(tfprotov6.ProviderServerWithResourceIdentity) + + if !ok { + resp.Diagnostics = append(resp.Diagnostics, &tfprotov6.Diagnostic{ + Severity: tfprotov6.DiagnosticSeverityError, + Summary: "GetResourceIdentitySchemas Not Implemented", + Detail: "A GetResourceIdentitySchemas call was received by the provider, however the provider does not implement GetResourceIdentitySchemas. " + + "Either upgrade the provider to a version that implements GetResourceIdentitySchemas or this is a bug in Terraform that should be reported to the Terraform maintainers.", + }) + + continue + } + + resourceIdentitySchemas, err := resourceIdentityServer.GetResourceIdentitySchemas(ctx, req) if err != nil { return resp, fmt.Errorf("error calling GetResourceIdentitySchemas for %T: %w", server, err) } - resp.Diagnostics = append(resp.Diagnostics, resourceIdentityServer.Diagnostics...) + resp.Diagnostics = append(resp.Diagnostics, resourceIdentitySchemas.Diagnostics...) - for resourceIdentityType, schema := range resourceIdentityServer.IdentitySchemas { + for resourceIdentityType, schema := range resourceIdentitySchemas.IdentitySchemas { if _, ok := resp.IdentitySchemas[resourceIdentityType]; ok { resp.Diagnostics = append(resp.Diagnostics, resourceIdentityDuplicateError(resourceIdentityType)) From 5c45d40fa22d12e966424160353df0c160f18c0a Mon Sep 17 00:00:00 2001 From: Ansgar Mertens Date: Tue, 18 Feb 2025 09:28:00 +0100 Subject: [PATCH 18/25] remove unused error --- tf5muxserver/diagnostics.go | 10 ---------- tf6muxserver/diagnostics.go | 10 ---------- 2 files changed, 20 deletions(-) diff --git a/tf5muxserver/diagnostics.go b/tf5muxserver/diagnostics.go index b5818cc..014a738 100644 --- a/tf5muxserver/diagnostics.go +++ b/tf5muxserver/diagnostics.go @@ -113,13 +113,3 @@ func resourceIdentityDuplicateError(typeName string) *tfprotov5.Diagnostic { "Duplicate identity type for resource: " + typeName, } } - -func resourceIdentityMissingError(typeName string) *tfprotov5.Diagnostic { - return &tfprotov5.Diagnostic{ - Severity: tfprotov5.DiagnosticSeverityError, - Summary: "Resource Identity Not Implemented", - Detail: "The combined provider does not implement the requested resource identity type. " + - "This is always an issue in the provider implementation and should be reported to the provider developers.\n\n" + - "Missing identity type for resource: " + typeName, - } -} diff --git a/tf6muxserver/diagnostics.go b/tf6muxserver/diagnostics.go index 954fde3..36c706a 100644 --- a/tf6muxserver/diagnostics.go +++ b/tf6muxserver/diagnostics.go @@ -115,13 +115,3 @@ func resourceIdentityDuplicateError(typeName string) *tfprotov6.Diagnostic { "Duplicate identity type for resource: " + typeName, } } - -func resourceIdentityMissingError(typeName string) *tfprotov6.Diagnostic { - return &tfprotov6.Diagnostic{ - Severity: tfprotov6.DiagnosticSeverityError, - Summary: "Resource Identity Not Implemented", - Detail: "The combined provider does not implement the requested resource identity type. " + - "This is always an issue in the provider implementation and should be reported to the provider developers.\n\n" + - "Missing identity type for resource: " + typeName, - } -} From 5d5820e2c86a27e2d0d6dbabeb631a6b2c335dc9 Mon Sep 17 00:00:00 2001 From: Rain Kwan <91649079+rainkwan@users.noreply.github.com> Date: Tue, 18 Feb 2025 10:45:19 -0500 Subject: [PATCH 19/25] Update .golangci.yml --- .golangci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index a1def30..7853804 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -5,9 +5,9 @@ issues: linters: disable-all: true enable: + - copyloopvar - durationcheck - errcheck - - exportloopref - forcetypeassert - gofmt - gosimple @@ -19,7 +19,7 @@ linters: - paralleltest - predeclared - staticcheck - - tenv - unconvert - unparam - - unused \ No newline at end of file + - unused + - usetesting From df221624c60032bcbd3364cc5e58bf1456c16967 Mon Sep 17 00:00:00 2001 From: Rain Date: Tue, 18 Feb 2025 10:57:46 -0500 Subject: [PATCH 20/25] Updated for linters --- internal/tfprotov5tov6/tfprotov5tov6_test.go | 61 ------------------- internal/tfprotov6tov5/tfprotov6tov5_test.go | 61 ------------------- tf5muxserver/mux_server_GetFunctions_test.go | 1 - tf5muxserver/mux_server_GetMetadata_test.go | 1 - .../mux_server_GetProviderSchema_test.go | 1 - ..._server_GetResourceIdentitySchemas_test.go | 1 - .../mux_server_PrepareProviderConfig_test.go | 1 - tf5muxserver/mux_server_test.go | 1 - tf5to6server/tf5to6server_test.go | 1 - tf6muxserver/mux_server_GetFunctions_test.go | 1 - tf6muxserver/mux_server_GetMetadata_test.go | 1 - .../mux_server_GetProviderSchema_test.go | 1 - ..._server_GetResourceIdentitySchemas_test.go | 1 - .../mux_server_ValidateProviderConfig_test.go | 1 - tf6muxserver/mux_server_test.go | 1 - tf6to5server/tf6to5server_test.go | 1 - 16 files changed, 136 deletions(-) diff --git a/internal/tfprotov5tov6/tfprotov5tov6_test.go b/internal/tfprotov5tov6/tfprotov5tov6_test.go index 9370e3b..6bd36e8 100644 --- a/internal/tfprotov5tov6/tfprotov5tov6_test.go +++ b/internal/tfprotov5tov6/tfprotov5tov6_test.go @@ -203,7 +203,6 @@ func TestApplyResourceChangeRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -247,7 +246,6 @@ func TestApplyResourceChangeResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -289,7 +287,6 @@ func TestCallFunctionRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -327,7 +324,6 @@ func TestCallFunctionResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -365,7 +361,6 @@ func TestCloseEphemeralResourceRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -401,7 +396,6 @@ func TestCloseEphemeralResourceResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -455,7 +449,6 @@ func TestConfigureProviderRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -491,7 +484,6 @@ func TestConfigureProviderResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -553,7 +545,6 @@ func TestDiagnostics(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -591,7 +582,6 @@ func TestDynamicValue(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -627,7 +617,6 @@ func TestResourceIdentityData(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -691,7 +680,6 @@ func TestFunction(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -723,7 +711,6 @@ func TestFunctionMetadata(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -763,7 +750,6 @@ func TestFunctionParameter(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -799,7 +785,6 @@ func TestFunctionReturn(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -831,7 +816,6 @@ func TestGetFunctionsRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -873,7 +857,6 @@ func TestGetFunctionsResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -905,7 +888,6 @@ func TestGetMetadataRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -965,7 +947,6 @@ func TestGetMetadataResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -997,7 +978,6 @@ func TestGetProviderSchemaRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -1061,7 +1041,6 @@ func TestGetProviderSchemaResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -1093,7 +1072,6 @@ func TestGetResourceIdentitySchemasRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -1135,7 +1113,6 @@ func TestGetResourceIdentitySchemasResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -1191,7 +1168,6 @@ func TestImportResourceStateRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -1271,7 +1247,6 @@ func TestImportResourceStateResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -1348,7 +1323,6 @@ func TestImportedResources(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -1400,7 +1374,6 @@ func TestMoveResourceStateRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -1442,7 +1415,6 @@ func TestMoveResourceStateResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -1496,7 +1468,6 @@ func TestOpenEphemeralResourceRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -1554,7 +1525,6 @@ func TestOpenEphemeralResourceResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -1628,7 +1598,6 @@ func TestPlanResourceChangeRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -1706,7 +1675,6 @@ func TestPlanResourceChangeResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -1744,7 +1712,6 @@ func TestRawState(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -1780,7 +1747,6 @@ func TestRawIdentity(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -1838,7 +1804,6 @@ func TestReadDataSourceRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -1892,7 +1857,6 @@ func TestReadDataSourceResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -1958,7 +1922,6 @@ func TestReadResourceRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2020,7 +1983,6 @@ func TestReadResourceResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2058,7 +2020,6 @@ func TestRenewEphemeralResourceRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2098,7 +2059,6 @@ func TestRenewEphemeralResourceResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2130,7 +2090,6 @@ func TestSchema(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2184,7 +2143,6 @@ func TestSchemaAttribute(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2264,7 +2222,6 @@ func TestSchemaBlock(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2322,7 +2279,6 @@ func TestSchemaNestedBlock(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2354,7 +2310,6 @@ func TestResourceIdentitySchema(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2398,7 +2353,6 @@ func TestResourceIdentitySchemaAttribute(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2430,7 +2384,6 @@ func TestStopProviderRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2466,7 +2419,6 @@ func TestStopProviderResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2498,7 +2450,6 @@ func TestStringKind(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2542,7 +2493,6 @@ func TestUpgradeResourceStateRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2580,7 +2530,6 @@ func TestUpgradeResourceStateResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2624,7 +2573,6 @@ func TestUpgradeResourceIdentityRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2662,7 +2610,6 @@ func TestUpgradeResourceIdentityResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2700,7 +2647,6 @@ func TestValidateDataResourceConfigRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2736,7 +2682,6 @@ func TestValidateDataResourceConfigResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2774,7 +2719,6 @@ func TestValidateEphemeralResourceConfigRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2810,7 +2754,6 @@ func TestValidateEphemeralResourceConfigResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2846,7 +2789,6 @@ func TestValidateProviderConfigRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2884,7 +2826,6 @@ func TestValidateProviderConfigResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2938,7 +2879,6 @@ func TestValidateResourceConfigRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2974,7 +2914,6 @@ func TestValidateResourceConfigResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() diff --git a/internal/tfprotov6tov5/tfprotov6tov5_test.go b/internal/tfprotov6tov5/tfprotov6tov5_test.go index 977f202..a1e5e3b 100644 --- a/internal/tfprotov6tov5/tfprotov6tov5_test.go +++ b/internal/tfprotov6tov5/tfprotov6tov5_test.go @@ -205,7 +205,6 @@ func TestApplyResourceChangeRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -249,7 +248,6 @@ func TestApplyResourceChangeResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -291,7 +289,6 @@ func TestCallFunctionRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -329,7 +326,6 @@ func TestCallFunctionResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -367,7 +363,6 @@ func TestCloseEphemeralResourceRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -403,7 +398,6 @@ func TestCloseEphemeralResourceResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -457,7 +451,6 @@ func TestConfigureProviderRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -493,7 +486,6 @@ func TestConfigureProviderResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -555,7 +547,6 @@ func TestDiagnostics(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -593,7 +584,6 @@ func TestDynamicValue(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -629,7 +619,6 @@ func TestResourceIdentityData(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -693,7 +682,6 @@ func TestFunction(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -725,7 +713,6 @@ func TestFunctionMetadata(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -765,7 +752,6 @@ func TestFunctionParameter(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -801,7 +787,6 @@ func TestFunctionReturn(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -833,7 +818,6 @@ func TestGetFunctionsRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -875,7 +859,6 @@ func TestGetFunctionsResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -907,7 +890,6 @@ func TestGetMetadataRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -967,7 +949,6 @@ func TestGetMetadataResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -999,7 +980,6 @@ func TestGetProviderSchemaRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -1190,7 +1170,6 @@ func TestGetProviderSchemaResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -1234,7 +1213,6 @@ func TestGetResourceIdentitySchemasRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -1276,7 +1254,6 @@ func TestGetResourceIdentitySchemasResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -1332,7 +1309,6 @@ func TestImportResourceStateRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -1412,7 +1388,6 @@ func TestImportResourceStateResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -1489,7 +1464,6 @@ func TestImportedResources(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -1541,7 +1515,6 @@ func TestMoveResourceStateRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -1583,7 +1556,6 @@ func TestMoveResourceStateResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -1637,7 +1609,6 @@ func TestOpenEphemeralResourceRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -1695,7 +1666,6 @@ func TestOpenEphemeralResourceResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -1769,7 +1739,6 @@ func TestPlanResourceChangeRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -1847,7 +1816,6 @@ func TestPlanResourceChangeResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -1883,7 +1851,6 @@ func TestPrepareProviderConfigRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -1921,7 +1888,6 @@ func TestPrepareProviderConfigResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -1959,7 +1925,6 @@ func TestRawState(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -1995,7 +1960,6 @@ func TestRawIdentity(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2053,7 +2017,6 @@ func TestReadDataSourceRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2107,7 +2070,6 @@ func TestReadDataSourceResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2173,7 +2135,6 @@ func TestReadResourceRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2235,7 +2196,6 @@ func TestReadResourceResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2273,7 +2233,6 @@ func TestRenewEphemeralResourceRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2313,7 +2272,6 @@ func TestRenewEphemeralResourceResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2368,7 +2326,6 @@ func TestSchema(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2451,7 +2408,6 @@ func TestSchemaAttribute(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2564,7 +2520,6 @@ func TestSchemaBlock(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2659,7 +2614,6 @@ func TestSchemaNestedBlock(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2703,7 +2657,6 @@ func TestResourceIdentitySchema(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2747,7 +2700,6 @@ func TestResourceIdentitySchemaAttribute(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2779,7 +2731,6 @@ func TestStopProviderRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2815,7 +2766,6 @@ func TestStopProviderResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2847,7 +2797,6 @@ func TestStringKind(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2891,7 +2840,6 @@ func TestUpgradeResourceStateRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2929,7 +2877,6 @@ func TestUpgradeResourceStateResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -2973,7 +2920,6 @@ func TestUpgradeResourceIdentityRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -3011,7 +2957,6 @@ func TestUpgradeResourceIdentityResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -3049,7 +2994,6 @@ func TestValidateDataSourceConfigRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -3085,7 +3029,6 @@ func TestValidateDataSourceConfigResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -3123,7 +3066,6 @@ func TestValidateEphemeralResourceConfigRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -3159,7 +3101,6 @@ func TestValidateEphemeralResourceConfigResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -3213,7 +3154,6 @@ func TestValidateResourceTypeConfigRequest(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() @@ -3249,7 +3189,6 @@ func TestValidateResourceTypeConfigResponse(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() diff --git a/tf5muxserver/mux_server_GetFunctions_test.go b/tf5muxserver/mux_server_GetFunctions_test.go index 0c65873..f164d0b 100644 --- a/tf5muxserver/mux_server_GetFunctions_test.go +++ b/tf5muxserver/mux_server_GetFunctions_test.go @@ -300,7 +300,6 @@ func TestMuxServerGetFunctions(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() diff --git a/tf5muxserver/mux_server_GetMetadata_test.go b/tf5muxserver/mux_server_GetMetadata_test.go index 2e02960..604b628 100644 --- a/tf5muxserver/mux_server_GetMetadata_test.go +++ b/tf5muxserver/mux_server_GetMetadata_test.go @@ -575,7 +575,6 @@ func TestMuxServerGetMetadata(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() diff --git a/tf5muxserver/mux_server_GetProviderSchema_test.go b/tf5muxserver/mux_server_GetProviderSchema_test.go index 2ee470f..52eb6bc 100644 --- a/tf5muxserver/mux_server_GetProviderSchema_test.go +++ b/tf5muxserver/mux_server_GetProviderSchema_test.go @@ -1157,7 +1157,6 @@ func TestMuxServerGetProviderSchema(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() diff --git a/tf5muxserver/mux_server_GetResourceIdentitySchemas_test.go b/tf5muxserver/mux_server_GetResourceIdentitySchemas_test.go index 1b154a0..879609d 100644 --- a/tf5muxserver/mux_server_GetResourceIdentitySchemas_test.go +++ b/tf5muxserver/mux_server_GetResourceIdentitySchemas_test.go @@ -335,7 +335,6 @@ func TestMuxServerGetResourceIdentitySchema(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() diff --git a/tf5muxserver/mux_server_PrepareProviderConfig_test.go b/tf5muxserver/mux_server_PrepareProviderConfig_test.go index 161c0fd..50d6673 100644 --- a/tf5muxserver/mux_server_PrepareProviderConfig_test.go +++ b/tf5muxserver/mux_server_PrepareProviderConfig_test.go @@ -398,7 +398,6 @@ func TestMuxServerPrepareProviderConfig(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() diff --git a/tf5muxserver/mux_server_test.go b/tf5muxserver/mux_server_test.go index 2eadd66..94a37f8 100644 --- a/tf5muxserver/mux_server_test.go +++ b/tf5muxserver/mux_server_test.go @@ -1787,7 +1787,6 @@ func TestNewMuxServer(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() diff --git a/tf5to6server/tf5to6server_test.go b/tf5to6server/tf5to6server_test.go index 66704d9..d1b308e 100644 --- a/tf5to6server/tf5to6server_test.go +++ b/tf5to6server/tf5to6server_test.go @@ -108,7 +108,6 @@ func TestUpgradeServer(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() diff --git a/tf6muxserver/mux_server_GetFunctions_test.go b/tf6muxserver/mux_server_GetFunctions_test.go index 0168acc..0c09c41 100644 --- a/tf6muxserver/mux_server_GetFunctions_test.go +++ b/tf6muxserver/mux_server_GetFunctions_test.go @@ -300,7 +300,6 @@ func TestMuxServerGetFunctions(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() diff --git a/tf6muxserver/mux_server_GetMetadata_test.go b/tf6muxserver/mux_server_GetMetadata_test.go index ffb02c9..6449e63 100644 --- a/tf6muxserver/mux_server_GetMetadata_test.go +++ b/tf6muxserver/mux_server_GetMetadata_test.go @@ -575,7 +575,6 @@ func TestMuxServerGetMetadata(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() diff --git a/tf6muxserver/mux_server_GetProviderSchema_test.go b/tf6muxserver/mux_server_GetProviderSchema_test.go index 346ba27..2e83699 100644 --- a/tf6muxserver/mux_server_GetProviderSchema_test.go +++ b/tf6muxserver/mux_server_GetProviderSchema_test.go @@ -1156,7 +1156,6 @@ func TestMuxServerGetProviderSchema(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() diff --git a/tf6muxserver/mux_server_GetResourceIdentitySchemas_test.go b/tf6muxserver/mux_server_GetResourceIdentitySchemas_test.go index 3e1facd..a13f5fc 100644 --- a/tf6muxserver/mux_server_GetResourceIdentitySchemas_test.go +++ b/tf6muxserver/mux_server_GetResourceIdentitySchemas_test.go @@ -335,7 +335,6 @@ func TestMuxServerGetResourceIdentitySchema(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() diff --git a/tf6muxserver/mux_server_ValidateProviderConfig_test.go b/tf6muxserver/mux_server_ValidateProviderConfig_test.go index 3f24fa0..5e58be0 100644 --- a/tf6muxserver/mux_server_ValidateProviderConfig_test.go +++ b/tf6muxserver/mux_server_ValidateProviderConfig_test.go @@ -415,7 +415,6 @@ func TestMuxServerValidateProviderConfig(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() diff --git a/tf6muxserver/mux_server_test.go b/tf6muxserver/mux_server_test.go index 54e45df..55f731a 100644 --- a/tf6muxserver/mux_server_test.go +++ b/tf6muxserver/mux_server_test.go @@ -1787,7 +1787,6 @@ func TestNewMuxServer(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() diff --git a/tf6to5server/tf6to5server_test.go b/tf6to5server/tf6to5server_test.go index 7d0f172..326c78f 100644 --- a/tf6to5server/tf6to5server_test.go +++ b/tf6to5server/tf6to5server_test.go @@ -206,7 +206,6 @@ func TestDowngradeServer(t *testing.T) { } for name, testCase := range testCases { - name, testCase := name, testCase t.Run(name, func(t *testing.T) { t.Parallel() From 7bf12e886c2da4c9c05163c075dfaac39e359b9f Mon Sep 17 00:00:00 2001 From: Rain Date: Tue, 18 Feb 2025 11:33:09 -0500 Subject: [PATCH 21/25] Added changelog --- .changes/unreleased/FEATURES-20250218-113243.yaml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changes/unreleased/FEATURES-20250218-113243.yaml diff --git a/.changes/unreleased/FEATURES-20250218-113243.yaml b/.changes/unreleased/FEATURES-20250218-113243.yaml new file mode 100644 index 0000000..fa474c8 --- /dev/null +++ b/.changes/unreleased/FEATURES-20250218-113243.yaml @@ -0,0 +1,5 @@ +kind: FEATURES +body: 'tf5muxserver+tf6muxserver+tf6to5server+tf5to6server: Upgraded protocols and added types to support the new resource identity feature' +time: 2025-02-18T11:32:43.959465-05:00 +custom: + Issue: "278" From ab74492e9e8a1e6db8185ba1e4c474605915c57d Mon Sep 17 00:00:00 2001 From: Rain Kwan <91649079+rainkwan@users.noreply.github.com> Date: Wed, 19 Feb 2025 15:42:06 -0500 Subject: [PATCH 22/25] Update tf5muxserver/mux_server_GetResourceIdentitySchemas.go Co-authored-by: Austin Valle --- tf5muxserver/mux_server_GetResourceIdentitySchemas.go | 1 - 1 file changed, 1 deletion(-) diff --git a/tf5muxserver/mux_server_GetResourceIdentitySchemas.go b/tf5muxserver/mux_server_GetResourceIdentitySchemas.go index 77a1cd8..a0e0286 100644 --- a/tf5muxserver/mux_server_GetResourceIdentitySchemas.go +++ b/tf5muxserver/mux_server_GetResourceIdentitySchemas.go @@ -67,7 +67,6 @@ func (s *muxServer) GetResourceIdentitySchemas(ctx context.Context, req *tfproto } } - s.serverDiscoveryComplete = true return resp, nil } From 4957a7eda9b2fb2c21319359815f5e86c12d1abe Mon Sep 17 00:00:00 2001 From: Rain Date: Wed, 19 Feb 2025 17:58:32 -0500 Subject: [PATCH 23/25] Chore: removed extra line triggering linter --- tf5muxserver/mux_server_GetResourceIdentitySchemas.go | 1 - 1 file changed, 1 deletion(-) diff --git a/tf5muxserver/mux_server_GetResourceIdentitySchemas.go b/tf5muxserver/mux_server_GetResourceIdentitySchemas.go index a0e0286..55d6732 100644 --- a/tf5muxserver/mux_server_GetResourceIdentitySchemas.go +++ b/tf5muxserver/mux_server_GetResourceIdentitySchemas.go @@ -67,6 +67,5 @@ func (s *muxServer) GetResourceIdentitySchemas(ctx context.Context, req *tfproto } } - return resp, nil } From 257d83a9964e1d2c017bbdf4bdd6b79d7045e07a Mon Sep 17 00:00:00 2001 From: Ansgar Mertens Date: Mon, 24 Feb 2025 15:23:09 +0100 Subject: [PATCH 24/25] remove server discovery locking which wasn't needed --- tf5muxserver/mux_server_GetResourceIdentitySchemas.go | 3 --- tf6muxserver/mux_server_GetResourceIdentitySchemas.go | 5 ----- 2 files changed, 8 deletions(-) diff --git a/tf5muxserver/mux_server_GetResourceIdentitySchemas.go b/tf5muxserver/mux_server_GetResourceIdentitySchemas.go index 55d6732..dcd576f 100644 --- a/tf5muxserver/mux_server_GetResourceIdentitySchemas.go +++ b/tf5muxserver/mux_server_GetResourceIdentitySchemas.go @@ -21,9 +21,6 @@ func (s *muxServer) GetResourceIdentitySchemas(ctx context.Context, req *tfproto ctx = logging.InitContext(ctx) ctx = logging.RpcContext(ctx, rpc) - s.serverDiscoveryMutex.Lock() - defer s.serverDiscoveryMutex.Unlock() - resp := &tfprotov5.GetResourceIdentitySchemasResponse{ IdentitySchemas: map[string]*tfprotov5.ResourceIdentitySchema{}, Diagnostics: []*tfprotov5.Diagnostic{}, diff --git a/tf6muxserver/mux_server_GetResourceIdentitySchemas.go b/tf6muxserver/mux_server_GetResourceIdentitySchemas.go index 5b72f07..a4697c6 100644 --- a/tf6muxserver/mux_server_GetResourceIdentitySchemas.go +++ b/tf6muxserver/mux_server_GetResourceIdentitySchemas.go @@ -21,9 +21,6 @@ func (s *muxServer) GetResourceIdentitySchemas(ctx context.Context, req *tfproto ctx = logging.InitContext(ctx) ctx = logging.RpcContext(ctx, rpc) - s.serverDiscoveryMutex.Lock() - defer s.serverDiscoveryMutex.Unlock() - resp := &tfprotov6.GetResourceIdentitySchemasResponse{ IdentitySchemas: map[string]*tfprotov6.ResourceIdentitySchema{}, Diagnostics: []*tfprotov6.Diagnostic{}, @@ -67,7 +64,5 @@ func (s *muxServer) GetResourceIdentitySchemas(ctx context.Context, req *tfproto } } - s.serverDiscoveryComplete = true - return resp, nil } From 5de4f2667f9722e03c873bb92ab11d0bf8a89aa7 Mon Sep 17 00:00:00 2001 From: Ansgar Mertens Date: Mon, 24 Feb 2025 15:25:02 +0100 Subject: [PATCH 25/25] remove unnecessary test server func --- internal/tf5testserver/tf5testserver.go | 5 ----- internal/tf6testserver/tf6testserver.go | 6 +----- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/internal/tf5testserver/tf5testserver.go b/internal/tf5testserver/tf5testserver.go index 4827f33..ee70718 100644 --- a/internal/tf5testserver/tf5testserver.go +++ b/internal/tf5testserver/tf5testserver.go @@ -273,8 +273,3 @@ func (s *TestServer) PrepareProviderConfig(_ context.Context, req *tfprotov5.Pre s.PrepareProviderConfigCalled = true return s.PrepareProviderConfigResponse, nil } - -//nolint:staticcheck // Intentionally verifying interface implementation -func (s *TestServer) ProviderServerWithResourceIdentity() tfprotov5.ProviderServerWithResourceIdentity { - return s -} diff --git a/internal/tf6testserver/tf6testserver.go b/internal/tf6testserver/tf6testserver.go index 2eaa0a6..c908588 100644 --- a/internal/tf6testserver/tf6testserver.go +++ b/internal/tf6testserver/tf6testserver.go @@ -5,6 +5,7 @@ package tf6testserver import ( "context" + "github.com/hashicorp/terraform-plugin-go/tfprotov6" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -272,8 +273,3 @@ func (s *TestServer) ValidateProviderConfig(_ context.Context, req *tfprotov6.Va s.ValidateProviderConfigCalled = true return s.ValidateProviderConfigResponse, nil } - -//nolint:staticcheck // Intentionally verifying interface implementation -func (s *TestServer) ProviderServerWithResourceIdentity() tfprotov6.ProviderServerWithResourceIdentity { - return s -}