Skip to content

Commit

Permalink
add instrumentation to inject user-agent header;
Browse files Browse the repository at this point in the history
update changelog;
update neon sdk.

Signed-off-by: Dmitry Kisler <admin@dkisler.com>
  • Loading branch information
kislerdm committed Oct 22, 2024
1 parent 068e6a7 commit 9407da7
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 14 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [v0.6.3] - Unreleased

### Added

- Added the "User-Agent" header injected to every request to the Neon API for tracking purposes as agreed with
James Broadhead from Neon.

### Changed

- Updated dependencies:
- Neon Go SDK: [v0.7.0](https://github.com/kislerdm/neon-sdk-go/compare/v0.6.1...v0.7.0)

## [v0.6.2] - 2024-10-04

### Added
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ require (
github.com/hashicorp/terraform-plugin-docs v0.19.4
github.com/hashicorp/terraform-plugin-log v0.9.0
github.com/hashicorp/terraform-plugin-sdk/v2 v2.33.0
github.com/kislerdm/neon-sdk-go v0.6.1
github.com/kislerdm/neon-sdk-go v0.7.0
github.com/stretchr/testify v1.8.2
)

Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/kislerdm/neon-sdk-go v0.6.1 h1:ILnqrZzRsjbAnxXOx3wb9HKUGR21pv14Y7U3yibUN00=
github.com/kislerdm/neon-sdk-go v0.6.1/go.mod h1:WSwEZ7oeR5KfQoCuDh/04LZxnSKDcvfsZyfG/QicDb8=
github.com/kislerdm/neon-sdk-go v0.7.0 h1:Xboh1mZO0jM8ss6u6iuVBkgBk9rXeq0PyoNisxi/fUA=
github.com/kislerdm/neon-sdk-go v0.7.0/go.mod h1:WSwEZ7oeR5KfQoCuDh/04LZxnSKDcvfsZyfG/QicDb8=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
Expand Down
54 changes: 42 additions & 12 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package provider

import (
"context"
"fmt"
"math/rand"
"net/http"
"os"
Expand Down Expand Up @@ -68,6 +69,10 @@ func newDev() *schema.Provider {
}

func New(version string) *schema.Provider {
return newWithClient(version, nil)
}

func newWithClient(version string, customHTTPClient neon.HTTPClient) *schema.Provider {
return &schema.Provider{
Schema: map[string]*schema.Schema{
"api_key": {
Expand All @@ -92,23 +97,48 @@ func New(version string) *schema.Provider {
"neon_branch_roles": dataSourceBranchRoles(),
"neon_branch_role_password": dataSourceBranchRolePassword(),
},
ConfigureContextFunc: configure(version),
ConfigureContextFunc: configure(version, customHTTPClient),
}
}

func configure(version string) schema.ConfigureContextFunc {
func configure(version string, httpClient neon.HTTPClient) schema.ConfigureContextFunc {
return func(ctx context.Context, d *schema.ResourceData) (interface{}, diag.Diagnostics) {
if version == "dev" {
c, err := neon.NewClient(neon.Config{HTTPClient: neon.NewMockHTTPClient()})
if err != nil {
return nil, diag.FromErr(err)
}
return c, diag.FromErr(err)
cfg := neon.Config{
Key: d.Get("api_key").(string),
}
c, err := neon.NewClient(neon.Config{Key: d.Get("api_key").(string)})
if err != nil {
return nil, diag.FromErr(err)

switch version {
case "dev":
cfg.HTTPClient = neon.NewMockHTTPClient()

default:
if httpClient == nil {
// The default timeout is set arbitrary to ensure the connection is shut during resources state update
httpClient = &http.Client{Timeout: 2 * time.Minute}
}

// Wrap the HTTP client into the client which injects the User-Agent header for tracing.
cfg.HTTPClient = httpClientWithUserAgent{httpClient: httpClient, providerVersion: version}
}
return c, nil

c, err := neon.NewClient(cfg)

return c, diag.FromErr(err)
}
}

type httpClientWithUserAgent struct {
httpClient neon.HTTPClient

providerVersion string
}

const DefaultApplicationName = "kislerdm/neon"

func (h httpClientWithUserAgent) Do(r *http.Request) (*http.Response, error) {
if r.Header == nil {
r.Header = make(http.Header)
}
r.Header.Set("User-Agent", fmt.Sprintf("tfProvider-%s@%s", DefaultApplicationName, h.providerVersion))
return h.httpClient.Do(r)
}
63 changes: 63 additions & 0 deletions internal/provider/provider_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//go:build !acceptance
// +build !acceptance

package provider

import (
"io"
"net/http"
"strings"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/stretchr/testify/assert"
)

type httpClient struct {
header http.Header
}

func (h *httpClient) Do(r *http.Request) (*http.Response, error) {
h.header = r.Header
return &http.Response{
StatusCode: http.StatusOK,
Body: io.NopCloser(strings.NewReader("{}")),
}, nil
}

func TestUserAgentInstrumentation(t *testing.T) {
const (
wantVersion = "ProviderVer"

resourceDefinition = `resource "neon_role" "this" {
project_id = "foo"
branch_id = "foo"
name = "foo"
}`
)

c := &httpClient{}

t.Setenv("NEON_API_KEY", "foo")

resource.UnitTest(t, resource.TestCase{
ProviderFactories: map[string]func() (*schema.Provider, error){
"neon": func() (*schema.Provider, error) {
return newWithClient(wantVersion, c), nil
},
},
Steps: []resource.TestStep{
{
Config: resourceDefinition,
ExpectNonEmptyPlan: true,
},
},
})

userAgent := c.header.Get("User-Agent")
assert.Contains(t, userAgent, DefaultApplicationName)
els := strings.Split(userAgent, "@")
assert.Len(t, els, 2)
assert.Equal(t, wantVersion, els[1])
}
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func main() {
opts := &plugin.ServeOpts{
Debug: debugMode,

ProviderAddr: "registry.terraform.io/kislerdm/neon",
ProviderAddr: "registry.terraform.io/" + provider.DefaultApplicationName,

ProviderFunc: func() *schema.Provider {
return provider.New(version)
Expand Down

0 comments on commit 9407da7

Please sign in to comment.