Skip to content

Commit

Permalink
ENH: Adds tcp service groups (#17)
Browse files Browse the repository at this point in the history
  • Loading branch information
thomasjpfan authored May 8, 2018
1 parent 0626e7d commit bbb0113
Show file tree
Hide file tree
Showing 14 changed files with 537 additions and 68 deletions.
20 changes: 18 additions & 2 deletions actions/reconfigure_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,22 @@ backend myService-be1234_12
s.Equal(expected, actual)
}

func (s ReconfigureTestSuite) Test_GetTemplates_ReturnsFormattedContent_WhenReqModeIsTcp_CheckTCP_InServiceDest() {
s.reconfigure.Service.ServiceDest[0].ReqMode = "tcp"
s.reconfigure.Service.ServiceDest[0].Port = "1234"
s.reconfigure.Service.ServiceDest[0].Index = 12
s.reconfigure.Service.ServiceDest[0].CheckTCP = true
expected := `
backend myService-be1234_12
mode tcp
option tcp-check
server myService myService:1234 check`

_, actual, _ := s.reconfigure.GetTemplates()

s.Equal(expected, actual)
}

func (s ReconfigureTestSuite) Test_GetTemplates_AddsHttpsPort_WhenPresent() {
expectedBack := `
backend myService-be1234_3
Expand Down Expand Up @@ -405,7 +421,7 @@ backend myService-be1234_4
server myService myService:1234`
s.reconfigure.ServiceDest[0].Port = "1234"
s.reconfigure.ServiceDest[0].Index = 4
s.reconfigure.TimeoutServer = "9999"
s.reconfigure.ServiceDest[0].TimeoutServer = "9999"
actualFront, actualBack, _ := s.reconfigure.GetTemplates()

s.Equal("", actualFront)
Expand All @@ -421,7 +437,7 @@ backend myService-be1234_3
server myService myService:1234`
s.reconfigure.ServiceDest[0].Port = "1234"
s.reconfigure.ServiceDest[0].Index = 3
s.reconfigure.TimeoutTunnel = "9999"
s.reconfigure.ServiceDest[0].TimeoutTunnel = "9999"
actualFront, actualBack, _ := s.reconfigure.GetTemplates()

s.Equal("", actualFront)
Expand Down
15 changes: 13 additions & 2 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ The following query parameters can be used to send a *reconfigure* request to *D
|timeoutTunnel |The tunnel timeout in seconds.<br>**Default:** `3600`<br>**Example:** `3600`|
|userDef |User defined value. This value is not used with current template. It is designed as a way to provide additional data that can be used with **custom templates**. The parameter must be prefixed with an index thus allowing definition of multiple destinations for a single service (e.g. `userDef.1`, `userDef.2`, and so on).|

Multiple destinations for a single service can be specified by adding index as a suffix to `servicePath`, `servicePathExclude`, `srcPort`, `port`, `userAgent`, `ignoreAuthorization`, `serviceDomain`, `allowedMethods`, `deniedMethods`, `denyHttp`, `httpsOnly`, `redirectFromDomain`, `reqMode`, `reqPathSearchReplace`, `outboundHostname`, `sslVerifyNone`, or `userDef` parameters. In that case, `srcPort` is required.
Multiple destinations for a single service can be specified by adding index as a suffix to `servicePath`, `servicePathExclude`, `srcPort`, `port`, `userAgent`, `ignoreAuthorization`, `serviceDomain`, `allowedMethods`, `deniedMethods`, `denyHttp`, `httpsOnly`, `redirectFromDomain`, `reqMode`, `reqPathSearchReplace`, `outboundHostname`, `sslVerifyNone`, `timeoutServer`, `timeoutTunnel`, or `userDef` parameters. In that case, `srcPort` is required.

### HTTP Mode Query Parameters

Expand Down Expand Up @@ -79,7 +79,17 @@ Multiple destinations for a single service can be specified by adding index as a

### TCP Mode HTTP Query Parameters

The `reqMode` set to `tcp` does not have any specific parameters beyond those specified in the [Reconfigure General Parameters](#reconfigure-general-parameters) section.
The following query parameters can be used only when `reqMode` is set to `tcp`.

|Query |Description |
|---------------|------------------------------------------------------------------------------------------|
|checkTcp |Checks tcp connection. Only used in sni or tcp mode.<br>**Example:** `True`|
|clitcpka |Enable sending of TCP keepalive packets on the client side. Only used in sni or tcp mode. <br>**Default value:** `false`|
|timeoutClient |The client timeout in seconds. This is only used when defining a tcp or sni frontend. To configure the http client timeout, use the `TIMEOUT_CLIENT` env var or the `dfp_timeout_client` secret. <br>**Default:** `20`<br>**Example:** `60`|
|serviceGroup |Name of TCP Group |
|balanceGroup |HAProxy balance mode for in TCP groups. Please consult the [HAPRoxy configuration page](https://cbonte.github.io/haproxy-dconv/1.8/configuration.html#4.2-balance) for all balance parameters|

Multiple destinations for a single service can be specified by adding index as a suffix to `servicePath`, `srcPort`, `port`, `serviceDomain`, `reqMode`, `outboundHostname`, `sslVerifyNone`, `timeoutServer`, `timeoutTunnel`, `timeoutClient`, `checkTcp`, `serviceGroup`, `balanceGroup`, `clitcpka` or `userDef` parameters. In that case, `srcPort` is required.

Please consult the [Using TCP Request Mode](swarm-mode-auto.md#using-tcp-request-mode) section for an example of working with `tcp` request mode.

Expand Down Expand Up @@ -146,6 +156,7 @@ The map between the HTTP query parameters and environment variables is as follow
|templateBePath |TEMPLATE_BE_PATH |
|templateFePath |TEMPLATE_FE_PATH |
|timeoutServer |TIMEOUT_SERVER |
|timeoutClient |TIMEOUT_CLIENT |
|timeoutTunnel |TIMEOUT_TUNNEL |
|users       |**Not supported** |
|usersSecret |**Not supported** |
Expand Down
2 changes: 1 addition & 1 deletion haproxy.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ defaults

option dontlognull
option dontlog-normal
option forwardfor
option redispatch

maxconn 5000
Expand All @@ -27,6 +26,7 @@ frontend dummy-fe
bind *:80
bind *:443
mode http
option forwardfor
option http-server-close
acl url_dummy path_beg /dummy
use_backend dummy-be if url_dummy
Expand Down
6 changes: 4 additions & 2 deletions haproxy.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ defaults
balance roundrobin
{{.ExtraDefaults}}
option {{.ConnectionMode}}
option forwardfor
option redispatch

errorfile 400 /errorfiles/400.http
Expand All @@ -44,4 +43,7 @@ defaults
{{.Stats}}
frontend services{{.DefaultBinds}}
mode {{.DefaultReqMode}}
{{.ExtraFrontend}}{{.ContentFrontend}}{{.ContentFrontendTcp}}{{.ContentFrontendSNI}}
{{- if eq .DefaultReqMode "http"}}
option forwardfor
{{- end}}
{{.ExtraFrontend}}{{.ContentFrontend}}{{.ContentFrontendTcp}}{{.ContentFrontendSNI}}{{.ContentListen}}
60 changes: 40 additions & 20 deletions proxy/ha_proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type configData struct {
ConnectionMode string
ContentFrontendSNI string
ContentFrontendTcp string
ContentListen string
DefaultBinds string
DefaultReqMode string
ExtraDefaults string
Expand Down Expand Up @@ -435,10 +436,23 @@ func (m *HaProxy) getUserList(data *configData) {
}
}

type tcpInfo struct {
ServiceName string
Port string
IPs []string
}

type tcpGroupInfo struct {
TargetService Service
TargetDest ServiceDest
TCPInfo []tcpInfo
}

func (m *HaProxy) getSni(services *Services, config *configData) {
sort.Sort(services)
snimap := make(map[int]string)
tcpFEs := make(map[int]Services)
tcpGroups := make(map[string]*tcpGroupInfo)
for _, s := range *services {
if len(s.ServiceDest) == 0 {
s.ServiceDest = []ServiceDest{{ReqMode: "http"}}
Expand All @@ -453,11 +467,34 @@ func (m *HaProxy) getSni(services *Services, config *configData) {
httpDone = true
} else if strings.EqualFold(sd.ReqMode, "sni") {
_, headerExists := snimap[sd.SrcPort]
snimap[sd.SrcPort] += m.getFrontTemplateSNI(s, i, !headerExists)
snimap[sd.SrcPort] += getFrontTemplateSNI(s, i, !headerExists)
} else if len(sd.ServiceGroup) > 0 {
tcpGroup, ok := tcpGroups[sd.ServiceGroup]
newIPs := []string{s.ServiceName}
if ips, err := lookupHost("tasks." + s.ServiceName); err == nil {
newIPs = ips
}
if !ok {
tcpGroups[sd.ServiceGroup] = &tcpGroupInfo{
TargetService: s,
TargetDest: sd,
TCPInfo: []tcpInfo{{
ServiceName: s.ServiceName,
Port: sd.Port,
IPs: newIPs,
}},
}
continue
}
tcpGroups[sd.ServiceGroup].TCPInfo = append(tcpGroup.TCPInfo, tcpInfo{
ServiceName: s.ServiceName,
Port: sd.Port,
IPs: newIPs,
})

} else {
tcpService := s
tcpService.ServiceDest = []ServiceDest{sd}
tcpService.AclCondition = fmt.Sprintf(" domain_%s", s.AclName)
if strings.EqualFold(os.Getenv("DEBUG"), "true") {
tcpService.Debug = true
tcpService.DebugFormat = getSecretOrEnvVar("DEBUG_TCP_FORMAT", "")
Expand All @@ -467,6 +504,7 @@ func (m *HaProxy) getSni(services *Services, config *configData) {
}
}
config.ContentFrontendTcp += getFrontTemplateTcp(tcpFEs)
config.ContentListen += getListenTCPGroup(tcpGroups)

// Merge the SNI entries into one single string. Sorted by port.
var sniports []int
Expand All @@ -479,24 +517,6 @@ func (m *HaProxy) getSni(services *Services, config *configData) {
}
}

// TODO: Refactor into template
func (m *HaProxy) getFrontTemplateSNI(s Service, si int, genHeader bool) string {
tmplString := ``
if genHeader {
tmplString += fmt.Sprintf(`{{$sd1 := index $.ServiceDest %d}}
frontend service_{{$sd1.SrcPort}}
bind *:{{$sd1.SrcPort}}
mode tcp
tcp-request inspect-delay 5s
tcp-request content accept if { req_ssl_hello_type 1 }`, si)
}
tmplString += fmt.Sprintf(`{{$sd := index $.ServiceDest %d}}
acl sni_{{.AclName}}{{$sd.Port}}-%d{{range $sd.ServicePath}} {{$.PathType}} {{.}}{{end}}{{$sd.SrcPortAcl}}
use_backend {{$.ServiceName}}-be{{$sd.Port}}_{{$sd.Index}} if sni_{{$.AclName}}{{$sd.Port}}-%d{{$.AclCondition}}{{$sd.SrcPortAclName}}`, si, si+1, si+1)
return templateToString(tmplString, s)
}

func (m *HaProxy) getReloadStrategy() string {
reloadStrategy := "-sf"
terminateOnReload := strings.EqualFold(os.Getenv("TERMINATE_ON_RELOAD"), "true")
Expand Down
Loading

0 comments on commit bbb0113

Please sign in to comment.