Skip to content

Commit 597d3e2

Browse files
committed
chore: Adds support for header value for tf-src/{resourceOrDataSourceName} in User-Agent
1 parent 764b788 commit 597d3e2

File tree

4 files changed

+155
-2
lines changed

4 files changed

+155
-2
lines changed

internal/config/client.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,12 @@ func (c *Config) NewClient(ctx context.Context) (any, error) {
103103
digestTransport := digest.NewTransportWithHTTPRoundTripper(cast.ToString(c.PublicKey), cast.ToString(c.PrivateKey), networkLoggingTransport)
104104
// Don't change logging.NewTransport to NewSubsystemLoggingHTTPTransport until all resources are in TPF.
105105
tfLoggingTransport := logging.NewTransport("Atlas", digestTransport)
106-
client := &http.Client{Transport: tfLoggingTransport}
106+
// Add tf-src header to User-Agent, see wrapper_provider_server.go
107+
// Must be before tfLoggingTransport otherwise the "final" userAgent will not be logged
108+
userAgentTransport := TFSrcUserAgentAdder{
109+
Transport: tfLoggingTransport,
110+
}
111+
client := &http.Client{Transport: &userAgentTransport}
107112

108113
optsAtlas := []matlasClient.ClientOpt{matlasClient.SetUserAgent(userAgent(c))}
109114
if c.BaseURL != "" {

internal/config/transport.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,37 @@
11
package config
22

33
import (
4+
"fmt"
45
"log"
56
"net/http"
67
"strings"
78
"time"
89
)
910

11+
type ContextKey string
12+
13+
const (
14+
ContextKeyTFSrc = ContextKey("tf-src")
15+
UserAgentHeader = "User-Agent"
16+
)
17+
18+
type TFSrcUserAgentAdder struct {
19+
Transport http.RoundTripper
20+
}
21+
22+
func (t *TFSrcUserAgentAdder) RoundTrip(req *http.Request) (*http.Response, error) {
23+
ctx := req.Context()
24+
tfSrcName := ctx.Value(ContextKeyTFSrc)
25+
if tfSrcName != nil {
26+
userAgent := req.Header.Get(UserAgentHeader)
27+
tfSrcValue := tfSrcName.(string)
28+
newVar := fmt.Sprintf("%s %s/%s", userAgent, ContextKeyTFSrc, tfSrcValue)
29+
req.Header.Set(UserAgentHeader, newVar)
30+
}
31+
resp, err := t.Transport.RoundTrip(req)
32+
return resp, err
33+
}
34+
1035
// NetworkLoggingTransport wraps an http.RoundTripper to provide enhanced logging
1136
// for network operations, including timing, status codes, and error details.
1237
type NetworkLoggingTransport struct {

internal/provider/provider.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,7 @@ func MuxProviderFactory() func() tfprotov6.ProviderServer {
506506
if err != nil {
507507
log.Fatal(err)
508508
}
509-
return muxServer.ProviderServer
509+
return NewWrappedProviderServer(muxServer.ProviderServer)
510510
}
511511

512512
func MultiEnvDefaultFunc(ks []string, def any) any {
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
package provider
2+
3+
import (
4+
"context"
5+
6+
"github.com/hashicorp/terraform-plugin-go/tfprotov6"
7+
"github.com/mongodb/terraform-provider-mongodbatlas/internal/config"
8+
)
9+
10+
func NewWrappedProviderServer(old func() tfprotov6.ProviderServer) func() tfprotov6.ProviderServer {
11+
return func() tfprotov6.ProviderServer {
12+
return &WrappedProviderServer{
13+
OldServer: old(),
14+
}
15+
}
16+
}
17+
18+
type WrappedProviderServer struct {
19+
OldServer tfprotov6.ProviderServer
20+
}
21+
22+
func (s *WrappedProviderServer) GetMetadata(ctx context.Context, req *tfprotov6.GetMetadataRequest) (*tfprotov6.GetMetadataResponse, error) {
23+
return s.OldServer.GetMetadata(ctx, req)
24+
}
25+
26+
func (s *WrappedProviderServer) GetProviderSchema(ctx context.Context, req *tfprotov6.GetProviderSchemaRequest) (*tfprotov6.GetProviderSchemaResponse, error) {
27+
return s.OldServer.GetProviderSchema(ctx, req)
28+
}
29+
30+
func (s *WrappedProviderServer) GetResourceIdentitySchemas(ctx context.Context, req *tfprotov6.GetResourceIdentitySchemasRequest) (*tfprotov6.GetResourceIdentitySchemasResponse, error) {
31+
return s.OldServer.GetResourceIdentitySchemas(ctx, req)
32+
}
33+
34+
func (s *WrappedProviderServer) ValidateProviderConfig(ctx context.Context, req *tfprotov6.ValidateProviderConfigRequest) (*tfprotov6.ValidateProviderConfigResponse, error) {
35+
return s.OldServer.ValidateProviderConfig(ctx, req)
36+
}
37+
38+
func (s *WrappedProviderServer) ConfigureProvider(ctx context.Context, req *tfprotov6.ConfigureProviderRequest) (*tfprotov6.ConfigureProviderResponse, error) {
39+
return s.OldServer.ConfigureProvider(ctx, req)
40+
}
41+
42+
func (s *WrappedProviderServer) StopProvider(ctx context.Context, req *tfprotov6.StopProviderRequest) (*tfprotov6.StopProviderResponse, error) {
43+
return s.OldServer.StopProvider(ctx, req)
44+
}
45+
46+
func (s *WrappedProviderServer) ValidateResourceConfig(ctx context.Context, req *tfprotov6.ValidateResourceConfigRequest) (*tfprotov6.ValidateResourceConfigResponse, error) {
47+
ctx = context.WithValue(ctx, config.ContextKeyTFSrc, req.TypeName)
48+
return s.OldServer.ValidateResourceConfig(ctx, req)
49+
}
50+
51+
func (s *WrappedProviderServer) UpgradeResourceState(ctx context.Context, req *tfprotov6.UpgradeResourceStateRequest) (*tfprotov6.UpgradeResourceStateResponse, error) {
52+
ctx = context.WithValue(ctx, config.ContextKeyTFSrc, "upgrade."+req.TypeName)
53+
return s.OldServer.UpgradeResourceState(ctx, req)
54+
}
55+
56+
func (s *WrappedProviderServer) ReadResource(ctx context.Context, req *tfprotov6.ReadResourceRequest) (*tfprotov6.ReadResourceResponse, error) {
57+
ctx = context.WithValue(ctx, config.ContextKeyTFSrc, req.TypeName)
58+
return s.OldServer.ReadResource(ctx, req)
59+
}
60+
61+
func (s *WrappedProviderServer) PlanResourceChange(ctx context.Context, req *tfprotov6.PlanResourceChangeRequest) (*tfprotov6.PlanResourceChangeResponse, error) {
62+
ctx = context.WithValue(ctx, config.ContextKeyTFSrc, req.TypeName)
63+
return s.OldServer.PlanResourceChange(ctx, req)
64+
}
65+
66+
func (s *WrappedProviderServer) ApplyResourceChange(ctx context.Context, req *tfprotov6.ApplyResourceChangeRequest) (*tfprotov6.ApplyResourceChangeResponse, error) {
67+
ctx = context.WithValue(ctx, config.ContextKeyTFSrc, req.TypeName)
68+
return s.OldServer.ApplyResourceChange(ctx, req)
69+
}
70+
71+
func (s *WrappedProviderServer) ImportResourceState(ctx context.Context, req *tfprotov6.ImportResourceStateRequest) (*tfprotov6.ImportResourceStateResponse, error) {
72+
ctx = context.WithValue(ctx, config.ContextKeyTFSrc, "import."+req.TypeName)
73+
return s.OldServer.ImportResourceState(ctx, req)
74+
}
75+
76+
func (s *WrappedProviderServer) MoveResourceState(ctx context.Context, req *tfprotov6.MoveResourceStateRequest) (*tfprotov6.MoveResourceStateResponse, error) {
77+
ctx = context.WithValue(ctx, config.ContextKeyTFSrc, "move."+req.TargetTypeName)
78+
return s.OldServer.MoveResourceState(ctx, req)
79+
}
80+
81+
func (s *WrappedProviderServer) UpgradeResourceIdentity(ctx context.Context, req *tfprotov6.UpgradeResourceIdentityRequest) (*tfprotov6.UpgradeResourceIdentityResponse, error) {
82+
ctx = context.WithValue(ctx, config.ContextKeyTFSrc, req.TypeName)
83+
return s.OldServer.UpgradeResourceIdentity(ctx, req)
84+
}
85+
86+
func (s *WrappedProviderServer) ValidateDataResourceConfig(ctx context.Context, req *tfprotov6.ValidateDataResourceConfigRequest) (*tfprotov6.ValidateDataResourceConfigResponse, error) {
87+
ctx = context.WithValue(ctx, config.ContextKeyTFSrc, "data."+req.TypeName)
88+
return s.OldServer.ValidateDataResourceConfig(ctx, req)
89+
}
90+
91+
func (s *WrappedProviderServer) ReadDataSource(ctx context.Context, req *tfprotov6.ReadDataSourceRequest) (*tfprotov6.ReadDataSourceResponse, error) {
92+
ctx = context.WithValue(ctx, config.ContextKeyTFSrc, "data."+req.TypeName)
93+
return s.OldServer.ReadDataSource(ctx, req)
94+
}
95+
96+
func (s *WrappedProviderServer) CallFunction(ctx context.Context, req *tfprotov6.CallFunctionRequest) (*tfprotov6.CallFunctionResponse, error) {
97+
ctx = context.WithValue(ctx, config.ContextKeyTFSrc, "func."+req.Name)
98+
return s.OldServer.CallFunction(ctx, req)
99+
}
100+
101+
func (s *WrappedProviderServer) GetFunctions(ctx context.Context, req *tfprotov6.GetFunctionsRequest) (*tfprotov6.GetFunctionsResponse, error) {
102+
return s.OldServer.GetFunctions(ctx, req)
103+
}
104+
105+
func (s *WrappedProviderServer) ValidateEphemeralResourceConfig(ctx context.Context, req *tfprotov6.ValidateEphemeralResourceConfigRequest) (*tfprotov6.ValidateEphemeralResourceConfigResponse, error) {
106+
ctx = context.WithValue(ctx, config.ContextKeyTFSrc, req.TypeName)
107+
return s.OldServer.ValidateEphemeralResourceConfig(ctx, req)
108+
}
109+
110+
func (s *WrappedProviderServer) OpenEphemeralResource(ctx context.Context, req *tfprotov6.OpenEphemeralResourceRequest) (*tfprotov6.OpenEphemeralResourceResponse, error) {
111+
ctx = context.WithValue(ctx, config.ContextKeyTFSrc, req.TypeName)
112+
return s.OldServer.OpenEphemeralResource(ctx, req)
113+
}
114+
115+
func (s *WrappedProviderServer) RenewEphemeralResource(ctx context.Context, req *tfprotov6.RenewEphemeralResourceRequest) (*tfprotov6.RenewEphemeralResourceResponse, error) {
116+
ctx = context.WithValue(ctx, config.ContextKeyTFSrc, req.TypeName)
117+
return s.OldServer.RenewEphemeralResource(ctx, req)
118+
}
119+
120+
func (s *WrappedProviderServer) CloseEphemeralResource(ctx context.Context, req *tfprotov6.CloseEphemeralResourceRequest) (*tfprotov6.CloseEphemeralResourceResponse, error) {
121+
ctx = context.WithValue(ctx, config.ContextKeyTFSrc, req.TypeName)
122+
return s.OldServer.CloseEphemeralResource(ctx, req)
123+
}

0 commit comments

Comments
 (0)