Support custom headers when fetching configuration through HTTP
This commit is contained in:
parent
188ef84c4f
commit
33f0aed5ea
7 changed files with 86 additions and 28 deletions
|
@ -76,6 +76,26 @@ providers:
|
|||
--providers.http.pollTimeout=5s
|
||||
```
|
||||
|
||||
### `headers`
|
||||
|
||||
_Optional_
|
||||
|
||||
Defines custom headers to be sent to the endpoint.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
providers:
|
||||
headers:
|
||||
name: value
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[providers.http.headers]
|
||||
name = "value"
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--providers.http.headers.name=value
|
||||
|
||||
### `tls`
|
||||
|
||||
_Optional_
|
||||
|
|
|
@ -645,6 +645,9 @@ Enable HTTP backend with default settings. (Default: ```false```)
|
|||
`--providers.http.endpoint`:
|
||||
Load configuration from this endpoint.
|
||||
|
||||
`--providers.http.headers.<name>`:
|
||||
Define custom headers to be sent to the endpoint.
|
||||
|
||||
`--providers.http.pollinterval`:
|
||||
Polling interval for endpoint. (Default: ```5```)
|
||||
|
||||
|
|
|
@ -645,6 +645,9 @@ Enable HTTP backend with default settings. (Default: ```false```)
|
|||
`TRAEFIK_PROVIDERS_HTTP_ENDPOINT`:
|
||||
Load configuration from this endpoint.
|
||||
|
||||
`TRAEFIK_PROVIDERS_HTTP_HEADERS_<NAME>`:
|
||||
Define custom headers to be sent to the endpoint.
|
||||
|
||||
`TRAEFIK_PROVIDERS_HTTP_POLLINTERVAL`:
|
||||
Polling interval for endpoint. (Default: ```5```)
|
||||
|
||||
|
|
|
@ -252,6 +252,9 @@
|
|||
endpoint = "foobar"
|
||||
pollInterval = "42s"
|
||||
pollTimeout = "42s"
|
||||
[providers.http.headers]
|
||||
name0 = "foobar"
|
||||
name1 = "foobar"
|
||||
[providers.http.tls]
|
||||
ca = "foobar"
|
||||
caOptional = true
|
||||
|
|
|
@ -280,6 +280,9 @@ providers:
|
|||
endpoint: foobar
|
||||
pollInterval: 42s
|
||||
pollTimeout: 42s
|
||||
headers:
|
||||
name0: foobar
|
||||
name1: foobar
|
||||
tls:
|
||||
ca: foobar
|
||||
caOptional: true
|
||||
|
|
|
@ -24,10 +24,12 @@ var _ provider.Provider = (*Provider)(nil)
|
|||
|
||||
// Provider is a provider.Provider implementation that queries an HTTP(s) endpoint for a configuration.
|
||||
type Provider struct {
|
||||
Endpoint string `description:"Load configuration from this endpoint." json:"endpoint" toml:"endpoint" yaml:"endpoint"`
|
||||
PollInterval ptypes.Duration `description:"Polling interval for endpoint." json:"pollInterval,omitempty" toml:"pollInterval,omitempty" yaml:"pollInterval,omitempty" export:"true"`
|
||||
PollTimeout ptypes.Duration `description:"Polling timeout for endpoint." json:"pollTimeout,omitempty" toml:"pollTimeout,omitempty" yaml:"pollTimeout,omitempty" export:"true"`
|
||||
TLS *types.ClientTLS `description:"Enable TLS support." json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" export:"true"`
|
||||
Endpoint string `description:"Load configuration from this endpoint." json:"endpoint" toml:"endpoint" yaml:"endpoint"`
|
||||
PollInterval ptypes.Duration `description:"Polling interval for endpoint." json:"pollInterval,omitempty" toml:"pollInterval,omitempty" yaml:"pollInterval,omitempty" export:"true"`
|
||||
PollTimeout ptypes.Duration `description:"Polling timeout for endpoint." json:"pollTimeout,omitempty" toml:"pollTimeout,omitempty" yaml:"pollTimeout,omitempty" export:"true"`
|
||||
Headers map[string]string `description:"Define custom headers to be sent to the endpoint." json:"headers,omitempty" toml:"headers,omitempty" yaml:"headers,omitempty" export:"true"`
|
||||
TLS *types.ClientTLS `description:"Enable TLS support." json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" export:"true"`
|
||||
|
||||
httpClient *http.Client
|
||||
lastConfigurationHash uint64
|
||||
}
|
||||
|
@ -139,9 +141,18 @@ func (p *Provider) updateConfiguration(configurationChan chan<- dynamic.Message)
|
|||
|
||||
// fetchConfigurationData fetches the configuration data from the configured endpoint.
|
||||
func (p *Provider) fetchConfigurationData() ([]byte, error) {
|
||||
res, err := p.httpClient.Get(p.Endpoint)
|
||||
req, err := http.NewRequest(http.MethodGet, p.Endpoint, http.NoBody)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("create fetch request: %w", err)
|
||||
}
|
||||
|
||||
for k, v := range p.Headers {
|
||||
req.Header.Set(k, v)
|
||||
}
|
||||
|
||||
res, err := p.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("do fetch request: %w", err)
|
||||
}
|
||||
|
||||
defer res.Body.Close()
|
||||
|
|
|
@ -69,35 +69,53 @@ func TestProvider_SetDefaults(t *testing.T) {
|
|||
|
||||
func TestProvider_fetchConfigurationData(t *testing.T) {
|
||||
tests := []struct {
|
||||
desc string
|
||||
handler func(rw http.ResponseWriter, req *http.Request)
|
||||
expData []byte
|
||||
expErr bool
|
||||
desc string
|
||||
statusCode int
|
||||
headers map[string]string
|
||||
expData []byte
|
||||
expErr require.ErrorAssertionFunc
|
||||
}{
|
||||
{
|
||||
desc: "should return the fetched configuration data",
|
||||
expData: []byte("{}"),
|
||||
handler: func(rw http.ResponseWriter, req *http.Request) {
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
_, _ = fmt.Fprintf(rw, "{}")
|
||||
},
|
||||
desc: "should return the fetched configuration data",
|
||||
statusCode: http.StatusOK,
|
||||
expData: []byte("{}"),
|
||||
expErr: require.NoError,
|
||||
},
|
||||
{
|
||||
desc: "should return an error if endpoint does not return an OK status code",
|
||||
expErr: true,
|
||||
handler: func(rw http.ResponseWriter, req *http.Request) {
|
||||
rw.WriteHeader(http.StatusNoContent)
|
||||
desc: "should send configured headers",
|
||||
statusCode: http.StatusOK,
|
||||
headers: map[string]string{
|
||||
"Foo": "bar",
|
||||
"Bar": "baz",
|
||||
},
|
||||
expData: []byte("{}"),
|
||||
expErr: require.NoError,
|
||||
},
|
||||
{
|
||||
desc: "should return an error if endpoint does not return an OK status code",
|
||||
statusCode: http.StatusInternalServerError,
|
||||
expErr: require.Error,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(test.handler))
|
||||
defer server.Close()
|
||||
handlerCalled := false
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
handlerCalled = true
|
||||
|
||||
for k, v := range test.headers {
|
||||
assert.Equal(t, v, req.Header.Get(k))
|
||||
}
|
||||
|
||||
rw.WriteHeader(test.statusCode)
|
||||
_, _ = rw.Write([]byte("{}"))
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
provider := Provider{
|
||||
Endpoint: server.URL,
|
||||
Endpoint: srv.URL,
|
||||
Headers: test.headers,
|
||||
PollInterval: ptypes.Duration(1 * time.Second),
|
||||
PollTimeout: ptypes.Duration(1 * time.Second),
|
||||
}
|
||||
|
@ -106,12 +124,9 @@ func TestProvider_fetchConfigurationData(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
configData, err := provider.fetchConfigurationData()
|
||||
if test.expErr {
|
||||
require.Error(t, err)
|
||||
return
|
||||
}
|
||||
test.expErr(t, err)
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.True(t, handlerCalled)
|
||||
assert.Equal(t, test.expData, configData)
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue