Skip to content

Commit cadfd60

Browse files
authored
chore: Add user agent headers to improve telemetry of Terraform usage (#86)
1 parent 062102e commit cadfd60

File tree

4 files changed

+90
-5
lines changed

4 files changed

+90
-5
lines changed

internal/provider/provider.go

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"terraform-provider-hookdeck/internal/provider/sourceverification"
1212
"terraform-provider-hookdeck/internal/provider/transformation"
1313
"terraform-provider-hookdeck/internal/provider/webhookregistration"
14+
"terraform-provider-hookdeck/internal/sdkclient"
1415

1516
"github.com/hashicorp/terraform-plugin-framework/datasource"
1617
"github.com/hashicorp/terraform-plugin-framework/path"
@@ -19,7 +20,6 @@ import (
1920
"github.com/hashicorp/terraform-plugin-framework/resource"
2021
"github.com/hashicorp/terraform-plugin-framework/types"
2122
"github.com/hashicorp/terraform-plugin-log/tflog"
22-
hookdeckClient "github.com/hookdeck/hookdeck-go-sdk/client"
2323
)
2424

2525
// Ensure the implementation satisfies various provider interfaces.
@@ -135,10 +135,7 @@ func (p *hookdeckProvider) Configure(ctx context.Context, req provider.Configure
135135
tflog.Debug(ctx, apiBase+" "+apiKey)
136136

137137
// Create a new Hookdeck client using the configuration values
138-
client := hookdeckClient.NewClient(
139-
hookdeckClient.WithBaseURL(apiBase),
140-
hookdeckClient.WithAuthToken(apiKey),
141-
)
138+
client := sdkclient.InitHookdeckSDKClient(apiBase, apiKey, p.version)
142139

143140
// Make the Hookdeck client available during DataSource and Resource
144141
// type Configure methods.

internal/sdkclient/sdkclient.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package sdkclient
2+
3+
import (
4+
"net/http"
5+
6+
hookdeckClient "github.com/hookdeck/hookdeck-go-sdk/client"
7+
)
8+
9+
func InitHookdeckSDKClient(apiBase string, apiKey string, providerVersion string) *hookdeckClient.Client {
10+
header := http.Header{}
11+
initUserAgentHeader(header, providerVersion)
12+
return hookdeckClient.NewClient(
13+
hookdeckClient.WithBaseURL(apiBase),
14+
hookdeckClient.WithAuthToken(apiKey),
15+
hookdeckClient.WithHTTPHeader(header),
16+
)
17+
}

internal/sdkclient/uname_unix.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//go:build !windows
2+
// +build !windows
3+
4+
package sdkclient
5+
6+
import (
7+
"bytes"
8+
"fmt"
9+
10+
"golang.org/x/sys/unix"
11+
)
12+
13+
func trimNulls(input []byte) []byte {
14+
return bytes.Trim(input, "\x00")
15+
}
16+
17+
func getUname() string {
18+
u := new(unix.Utsname)
19+
20+
err := unix.Uname(u)
21+
if err != nil {
22+
panic(err)
23+
}
24+
25+
return fmt.Sprintf("%s %s %s %s %s", trimNulls(u.Sysname[:]), trimNulls(u.Nodename[:]), trimNulls(u.Release[:]), trimNulls(u.Version[:]), trimNulls(u.Machine[:]))
26+
}

internal/sdkclient/useragent.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package sdkclient
2+
3+
import (
4+
"encoding/json"
5+
"net/http"
6+
"runtime"
7+
)
8+
9+
func initUserAgentHeader(header http.Header, providerVersion string) {
10+
header.Add("User-Agent", getUserAgent(providerVersion))
11+
header.Add("X-Hookdeck-Client-User-Agent", getHookdeckUserAgent(providerVersion))
12+
}
13+
14+
func getUserAgent(providerVersion string) string {
15+
return "Hookdeck/v1 terraform-provider-hookdeck/" + providerVersion
16+
}
17+
18+
// hookdeckClientUserAgent contains information about the current runtime which
19+
// is serialized and sent in the `X-Hookdeck-Client-User-Agent` as additional
20+
// debugging information.
21+
type hookdeckClientUserAgent struct {
22+
Name string `json:"name"`
23+
OS string `json:"os"`
24+
Publisher string `json:"publisher"`
25+
Uname string `json:"uname"`
26+
Version string `json:"version"`
27+
}
28+
29+
func getHookdeckUserAgent(providerVersion string) string {
30+
hookdeckUserAgent := &hookdeckClientUserAgent{
31+
Name: "terraform-provider-hookdeck",
32+
Version: providerVersion,
33+
Publisher: "hookdeck",
34+
OS: runtime.GOOS,
35+
Uname: getUname(),
36+
}
37+
marshaled, err := json.Marshal(hookdeckUserAgent)
38+
// Encoding this struct should never be a problem, so we're okay to panic
39+
// in case it is for some reason.
40+
if err != nil {
41+
panic(err)
42+
}
43+
44+
return string(marshaled)
45+
}

0 commit comments

Comments
 (0)