Skip to content

Commit

Permalink
Merge pull request #575 from jcmoraisjr/jm-headers
Browse files Browse the repository at this point in the history
Add headers config key
  • Loading branch information
jcmoraisjr authored May 19, 2020
2 parents 7cb0868 + d3260f3 commit ac0ab34
Show file tree
Hide file tree
Showing 9 changed files with 160 additions and 0 deletions.
23 changes: 23 additions & 0 deletions docs/content/en/docs/configuration/keys.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ The table below describes all supported configuration keys.
| [`dynamic-scaling`](#dynamic-scaling) | [true\|false] | Backend | `true` |
| [`forwardfor`](#forwardfor) | [add\|ignore\|ifmissing] | Global | `add` |
| [`fronting-proxy-port`](#fronting-proxy-port) | port number | Global | 0 (do not listen) |
| [`headers`](#headers) | multiline header:value pair | Backend | |
| [`health-check-addr`](#health-check) | address for health checks | Backend | |
| [`health-check-fall-count`](#health-check) | number of failures | Backend | |
| [`health-check-interval`](#health-check) | time with suffix | Backend | |
Expand Down Expand Up @@ -972,6 +973,28 @@ See also:
* [Bind](#bind)
* [Bind port](#bind-port)

## Headers

| Configuration key | Scope | Default | Since |
|-------------------|-----------|---------|--------|
| `headers` | `Backend` | | v0.11 |

Configures a list of HTTP header names and the value it should be configured with. More than one header can be configured using a multi-line configuration value. The name of the header and its value should be separated with a colon and/or any amount of spaces.

The following variables can be used in the value:

* `%[namespace]`: namespace of the ingress or service
* `%[service]`: name of the service which received the request

Configuration example:

```yaml
annotations:
ingress.kubernetes.io/headers: |
x-path: /
host: %[service].%[namespace].svc.cluster.local
```

---

## Health check
Expand Down
27 changes: 27 additions & 0 deletions pkg/converters/ingress/annotations/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,33 @@ func (c *updater) buildBackendHealthCheck(d *backData) {
d.backend.HealthCheck.URI = d.mapper.Get(ingtypes.BackHealthCheckURI).Value
}

func (c *updater) buildBackendHeaders(d *backData) {
headers := d.mapper.Get(ingtypes.BackHeaders)
if headers.Value == "" {
return
}
for _, header := range utils.LineToSlice(headers.Value) {
header = strings.TrimSpace(header)
if header == "" {
continue
}
idx := strings.IndexAny(header, ": ")
if idx <= 0 {
c.logger.Warn("ignored missing header name or value on %v: %s", headers.Source, header)
continue
}
name := strings.TrimRight(header[:idx], ":")
value := strings.TrimSpace(header[idx+1:])
// TODO this should use a structured type and a smart match/replace if growing a bit more
value = strings.ReplaceAll(value, "%[service]", d.backend.Name)
value = strings.ReplaceAll(value, "%[namespace]", d.backend.Namespace)
d.backend.Headers = append(d.backend.Headers, &hatypes.BackendHeader{
Name: name,
Value: value,
})
}
}

func (c *updater) buildBackendHSTS(d *backData) {
rawHSTSList := d.mapper.GetBackendConfig(
d.backend,
Expand Down
71 changes: 71 additions & 0 deletions pkg/converters/ingress/annotations/backend_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -911,6 +911,77 @@ func TestCors(t *testing.T) {
}
}

func TestHeaders(t *testing.T) {
testCases := []struct {
headers string
expected []*hatypes.BackendHeader
logging string
}{
// 0
{
headers: `invalid`,
logging: `WARN ignored missing header name or value on ingress 'ing1/app': invalid`,
},
// 1
{
headers: `key value`,
expected: []*hatypes.BackendHeader{
{Name: "key", Value: "value"},
},
},
// 2
{
headers: `name: content`,
expected: []*hatypes.BackendHeader{
{Name: "name", Value: "content"},
},
},
// 3
{
headers: `k:v`,
expected: []*hatypes.BackendHeader{
{Name: "k", Value: "v"},
},
},
// 4
{
headers: `host: %[service].%[namespace].svc.cluster.local`,
expected: []*hatypes.BackendHeader{
{Name: "host", Value: "app.default.svc.cluster.local"},
},
},
// 5
{
headers: `
k8snamespace: %[namespace]
k8sservice: %[service]
host: %[service].%[namespace].svc.cluster.local
`,
expected: []*hatypes.BackendHeader{
{Name: "k8snamespace", Value: "default"},
{Name: "k8sservice", Value: "app"},
{Name: "host", Value: "app.default.svc.cluster.local"},
},
},
}
source := &Source{
Namespace: "ing1",
Name: "app",
Type: "ingress",
}
for i, test := range testCases {
c := setup(t)
ann := map[string]map[string]string{
"/": {ingtypes.BackHeaders: test.headers},
}
d := c.createBackendMappingData("default/app", source, map[string]string{}, ann, []string{"/"})
c.createUpdater().buildBackendHeaders(d)
c.compareObjects("headers", i, d.backend.Headers, test.expected)
c.logger.CompareLogging(test.logging)
c.teardown()
}
}

func TestHSTS(t *testing.T) {
testCases := []struct {
paths []string
Expand Down
1 change: 1 addition & 0 deletions pkg/converters/ingress/annotations/updater.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ func (c *updater) UpdateBackendConfig(backend *hatypes.Backend, mapper *Mapper)
c.buildBackendDNS(data)
c.buildBackendDynamic(data)
c.buildBackendAgentCheck(data)
c.buildBackendHeaders(data)
c.buildBackendHealthCheck(data)
c.buildBackendHSTS(data)
c.buildBackendLimit(data)
Expand Down
1 change: 1 addition & 0 deletions pkg/converters/ingress/types/annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ const (
BackCorsExposeHeaders = "cors-expose-headers"
BackCorsMaxAge = "cors-max-age"
BackDynamicScaling = "dynamic-scaling"
BackHeaders = "headers"
BackHealthCheckAddr = "health-check-addr"
BackHealthCheckFallCount = "health-check-fall-count"
BackHealthCheckInterval = "health-check-interval"
Expand Down
20 changes: 20 additions & 0 deletions pkg/haproxy/instance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,26 @@ func TestBackends(t *testing.T) {
# path02 = d1.local/app
http-request set-var(txn.pathID) base,lower,map_beg(/etc/haproxy/maps/_back_d1_app_8080_idpath.map)
http-request use-service lua.send-413 if { var(txn.pathID) path02 } { req.body_size,sub(2048) gt 0 }`,
},
{
doconfig: func(g *hatypes.Global, h *hatypes.Host, b *hatypes.Backend) {
b.Headers = []*hatypes.BackendHeader{
{Name: "Name", Value: "Value"},
}
},
expected: `
http-request set-header Name Value`,
},
{
doconfig: func(g *hatypes.Global, h *hatypes.Host, b *hatypes.Backend) {
b.Headers = []*hatypes.BackendHeader{
{Name: "X-ID", Value: "abc"},
{Name: "Host", Value: "app.domain"},
}
},
expected: `
http-request set-header X-ID abc
http-request set-header Host app.domain`,
},
{
doconfig: func(g *hatypes.Global, h *hatypes.Host, b *hatypes.Backend) {
Expand Down
5 changes: 5 additions & 0 deletions pkg/haproxy/types/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,11 @@ func (p *BackendPath) String() string {
return fmt.Sprintf("%+v", *p)
}

// String ...
func (h *BackendHeader) String() string {
return fmt.Sprintf("%+v", *h)
}

// String ...
func (b *BackendConfigAuth) String() string {
return fmt.Sprintf("%+v", *b)
Expand Down
7 changes: 7 additions & 0 deletions pkg/haproxy/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,7 @@ type Backend struct {
Cookie Cookie
CustomConfig []string
Dynamic DynBackendConfig
Headers []*BackendHeader
HealthCheck HealthCheck
Limit BackendLimit
ModeTCP bool
Expand Down Expand Up @@ -456,6 +457,12 @@ type BackendPath struct {
Path string
}

// BackendHeader ...
type BackendHeader struct {
Name string
Value string
}

// BackendConfigBool ...
type BackendConfigBool struct {
Paths BackendPaths
Expand Down
5 changes: 5 additions & 0 deletions rootfs/etc/haproxy/template/haproxy.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,11 @@ backend {{ $backend.ID }}
{{- end }}
{{- end }}

{{- /*------------------------------------*/}}
{{- range $header := $backend.Headers }}
http-request set-header {{ $header.Name }} {{ $header.Value }}
{{- end }}

{{- /*------------------------------------*/}}
{{- if $backend.TLS.HasTLSAuth }}
{{- $needSSLACL := not $backend.HasSSLRedirect }}
Expand Down

0 comments on commit ac0ab34

Please sign in to comment.