Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
caddy
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Łukasz Nowak
caddy
Commits
078c9915
Commit
078c9915
authored
Jun 28, 2017
by
Martin Redmond
Committed by
Matt Holt
Jun 28, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
proxy: custom upstream health check by body string, closes #324 (#1691)
parent
bf7b2548
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
95 additions
and
20 deletions
+95
-20
caddyhttp/proxy/upstream.go
caddyhttp/proxy/upstream.go
+42
-20
caddyhttp/proxy/upstream_test.go
caddyhttp/proxy/upstream_test.go
+53
-0
No files found.
caddyhttp/proxy/upstream.go
View file @
078c9915
package
proxy
import
(
"bytes"
"fmt"
"io"
"io/ioutil"
...
...
@@ -38,12 +39,13 @@ type staticUpstream struct {
TryInterval
time
.
Duration
MaxConns
int64
HealthCheck
struct
{
Client
http
.
Client
Path
string
Interval
time
.
Duration
Timeout
time
.
Duration
Host
string
Port
string
Client
http
.
Client
Path
string
Interval
time
.
Duration
Timeout
time
.
Duration
Host
string
Port
string
ContentString
string
}
WithoutPathPrefix
string
IgnoredSubPaths
[]
string
...
...
@@ -337,6 +339,11 @@ func parseBlock(c *caddyfile.Dispenser, u *staticUpstream) error {
return
c
.
Errf
(
"invalid health_check_port '%s'"
,
port
)
}
u
.
HealthCheck
.
Port
=
port
case
"health_check_contains"
:
if
!
c
.
NextArg
()
{
return
c
.
ArgErr
()
}
u
.
HealthCheck
.
ContentString
=
c
.
Val
()
case
"header_upstream"
:
var
header
,
value
string
if
!
c
.
Args
(
&
header
,
&
value
)
{
...
...
@@ -402,27 +409,42 @@ func (u *staticUpstream) healthCheck() {
}
hostURL
+=
u
.
HealthCheck
.
Path
var
unhealthy
bool
// set up request, needed to be able to modify headers
// possible errors are bad HTTP methods or un-parsable urls
req
,
err
:=
http
.
NewRequest
(
"GET"
,
hostURL
,
nil
)
if
err
!=
nil
{
unhealthy
=
true
}
else
{
unhealthy
:=
func
()
bool
{
// set up request, needed to be able to modify headers
// possible errors are bad HTTP methods or un-parsable urls
req
,
err
:=
http
.
NewRequest
(
"GET"
,
hostURL
,
nil
)
if
err
!=
nil
{
return
true
}
// set host for request going upstream
if
u
.
HealthCheck
.
Host
!=
""
{
req
.
Host
=
u
.
HealthCheck
.
Host
}
if
r
,
err
:=
u
.
HealthCheck
.
Client
.
Do
(
req
);
err
==
nil
{
r
,
err
:=
u
.
HealthCheck
.
Client
.
Do
(
req
)
if
err
!=
nil
{
return
true
}
defer
func
()
{
io
.
Copy
(
ioutil
.
Discard
,
r
.
Body
)
r
.
Body
.
Close
()
unhealthy
=
r
.
StatusCode
<
200
||
r
.
StatusCode
>=
400
}
else
{
unhealthy
=
true
}()
if
r
.
StatusCode
<
200
||
r
.
StatusCode
>=
400
{
return
true
}
}
if
u
.
HealthCheck
.
ContentString
==
""
{
// don't check for content string
return
false
}
// TODO ReadAll will be replaced if deemed necessary
// See https://github.com/mholt/caddy/pull/1691
buf
,
err
:=
ioutil
.
ReadAll
(
r
.
Body
)
if
err
!=
nil
{
return
true
}
if
bytes
.
Contains
(
buf
,
[]
byte
(
u
.
HealthCheck
.
ContentString
))
{
return
false
}
return
true
}()
if
unhealthy
{
atomic
.
StoreInt32
(
&
host
.
Unhealthy
,
1
)
}
else
{
...
...
caddyhttp/proxy/upstream_test.go
View file @
078c9915
...
...
@@ -448,3 +448,56 @@ func TestHealthCheckPort(t *testing.T) {
})
}
func
TestHealthCheckContentString
(
t
*
testing
.
T
)
{
server
:=
httptest
.
NewServer
(
http
.
HandlerFunc
(
func
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
fmt
.
Fprintf
(
w
,
"blablabla good blablabla"
)
r
.
Body
.
Close
()
}))
_
,
port
,
err
:=
net
.
SplitHostPort
(
server
.
Listener
.
Addr
()
.
String
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
defer
server
.
Close
()
tests
:=
[]
struct
{
config
string
shouldContain
bool
}{
{
"proxy / localhost:"
+
port
+
" { health_check /testhealth "
+
" health_check_contains good
\n
}"
,
true
,
},
{
"proxy / localhost:"
+
port
+
" {
\n
health_check /testhealth health_check_port "
+
port
+
"
\n
health_check_contains bad
\n
}"
,
false
,
},
}
for
i
,
test
:=
range
tests
{
u
,
err
:=
NewStaticUpstreams
(
caddyfile
.
NewDispenser
(
"Testfile"
,
strings
.
NewReader
(
test
.
config
)),
""
)
if
err
!=
nil
{
t
.
Error
(
"Expected no error. Test %d Got:"
,
i
,
err
.
Error
())
}
for
_
,
upstream
:=
range
u
{
staticUpstream
,
ok
:=
upstream
.
(
*
staticUpstream
)
if
!
ok
{
t
.
Errorf
(
"Type mismatch: %#v"
,
upstream
)
continue
}
staticUpstream
.
healthCheck
()
for
_
,
host
:=
range
staticUpstream
.
Hosts
{
if
test
.
shouldContain
&&
atomic
.
LoadInt32
(
&
host
.
Unhealthy
)
==
0
{
// healthcheck url was hit and the required test string was found
continue
}
if
!
test
.
shouldContain
&&
atomic
.
LoadInt32
(
&
host
.
Unhealthy
)
!=
0
{
// healthcheck url was hit and the required string was not found
continue
}
t
.
Errorf
(
"Health check bad response"
)
}
upstream
.
Stop
()
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment