Skip to content

Commit 9aa734e

Browse files
Merge pull request #71 from DataDog/fix/66-custom-api-url
fix(config): skip api. prefix for on-call domains in DD_SITE
2 parents b564d8c + 47a8ba6 commit 9aa734e

3 files changed

Lines changed: 94 additions & 4 deletions

File tree

pkg/client/client.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ func NewWithOptions(cfg *config.Config, forceAPIKeys bool) (*Client, error) {
105105

106106
// Configure the API client
107107
configuration := datadog.NewConfiguration()
108-
configuration.Host = fmt.Sprintf("api.%s", cfg.Site)
108+
configuration.Host = cfg.GetAPIHost()
109109

110110
// Set custom user agent to identify requests as coming from pup CLI
111111
configuration.UserAgent = useragent.Get()
@@ -175,7 +175,7 @@ func (c *Client) RawRequest(method, path string, body io.Reader) (*http.Response
175175
return nil, err
176176
}
177177

178-
url := fmt.Sprintf("https://api.%s%s", c.config.Site, path)
178+
url := fmt.Sprintf("https://%s%s", c.config.GetAPIHost(), path)
179179

180180
req, err := http.NewRequest(method, url, body)
181181
if err != nil {

pkg/config/config.go

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ package config
88
import (
99
"fmt"
1010
"os"
11+
"strings"
1112
)
1213

1314
// Config holds the application configuration
@@ -41,9 +42,26 @@ func (c *Config) Validate() error {
4142
return nil
4243
}
4344

44-
// GetAPIURL returns the full API URL for the configured site
45+
// IsOnCallSite returns true if the site is an on-call domain (contains "oncall").
46+
// On-call domains like navy.oncall.datadoghq.com are already fully-qualified
47+
// and should not have "api." prepended.
48+
func IsOnCallSite(site string) bool {
49+
return strings.Contains(site, "oncall")
50+
}
51+
52+
// GetAPIURL returns the full API URL for the configured site.
53+
// On-call domains are used as-is; all other sites get "https://api.{site}".
4554
func (c *Config) GetAPIURL() string {
46-
return fmt.Sprintf("https://api.%s", c.Site)
55+
return "https://" + c.GetAPIHost()
56+
}
57+
58+
// GetAPIHost returns the host portion of the API URL (without scheme).
59+
// On-call domains are returned as-is; all other sites get "api.{site}".
60+
func (c *Config) GetAPIHost() string {
61+
if IsOnCallSite(c.Site) {
62+
return c.Site
63+
}
64+
return fmt.Sprintf("api.%s", c.Site)
4765
}
4866

4967
// getEnvWithDefault returns environment variable value or default if not set

pkg/config/config_test.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,17 @@ func TestLoad(t *testing.T) {
8282
wantSite: "datadoghq.com",
8383
wantApprove: false,
8484
},
85+
{
86+
name: "on-call domain via DD_SITE",
87+
envVars: map[string]string{
88+
"DD_API_KEY": "key",
89+
"DD_APP_KEY": "app",
90+
"DD_SITE": "navy.oncall.datadoghq.com",
91+
},
92+
wantAPIKey: "key",
93+
wantAppKey: "app",
94+
wantSite: "navy.oncall.datadoghq.com",
95+
},
8596
}
8697

8798
for _, tt := range tests {
@@ -176,6 +187,36 @@ func TestConfig_Validate(t *testing.T) {
176187
}
177188
}
178189

190+
func TestIsOnCallSite(t *testing.T) {
191+
t.Parallel()
192+
tests := []struct {
193+
name string
194+
site string
195+
want bool
196+
}{
197+
// Standard sites — not on-call
198+
{name: "US1", site: "datadoghq.com", want: false},
199+
{name: "EU", site: "datadoghq.eu", want: false},
200+
{name: "US3", site: "us3.datadoghq.com", want: false},
201+
{name: "Gov", site: "ddog-gov.com", want: false},
202+
203+
// On-call domains
204+
{name: "on-call navy", site: "navy.oncall.datadoghq.com", want: true},
205+
{name: "on-call army", site: "army.oncall.datadoghq.com", want: true},
206+
{name: "on-call staging", site: "test.oncall.datad0g.com", want: true},
207+
}
208+
209+
for _, tt := range tests {
210+
t.Run(tt.name, func(t *testing.T) {
211+
t.Parallel()
212+
got := IsOnCallSite(tt.site)
213+
if got != tt.want {
214+
t.Errorf("IsOnCallSite(%q) = %v, want %v", tt.site, got, tt.want)
215+
}
216+
})
217+
}
218+
}
219+
179220
func TestConfig_GetAPIURL(t *testing.T) {
180221
t.Parallel()
181222
tests := []struct {
@@ -218,6 +259,11 @@ func TestConfig_GetAPIURL(t *testing.T) {
218259
site: "datad0g.com",
219260
want: "https://api.datad0g.com",
220261
},
262+
{
263+
name: "on-call domain used as-is",
264+
site: "navy.oncall.datadoghq.com",
265+
want: "https://navy.oncall.datadoghq.com",
266+
},
221267
}
222268

223269
for _, tt := range tests {
@@ -232,6 +278,32 @@ func TestConfig_GetAPIURL(t *testing.T) {
232278
}
233279
}
234280

281+
func TestConfig_GetAPIHost(t *testing.T) {
282+
t.Parallel()
283+
tests := []struct {
284+
name string
285+
site string
286+
want string
287+
}{
288+
{name: "US1", site: "datadoghq.com", want: "api.datadoghq.com"},
289+
{name: "EU", site: "datadoghq.eu", want: "api.datadoghq.eu"},
290+
{name: "US3", site: "us3.datadoghq.com", want: "api.us3.datadoghq.com"},
291+
{name: "Gov", site: "ddog-gov.com", want: "api.ddog-gov.com"},
292+
{name: "on-call", site: "navy.oncall.datadoghq.com", want: "navy.oncall.datadoghq.com"},
293+
}
294+
295+
for _, tt := range tests {
296+
t.Run(tt.name, func(t *testing.T) {
297+
t.Parallel()
298+
cfg := &Config{Site: tt.site}
299+
got := cfg.GetAPIHost()
300+
if got != tt.want {
301+
t.Errorf("GetAPIHost() = %q, want %q", got, tt.want)
302+
}
303+
})
304+
}
305+
}
306+
235307
func TestGetEnvWithDefault(t *testing.T) {
236308
t.Parallel()
237309
// Save original

0 commit comments

Comments
 (0)