Skip to content

Commit

Permalink
Merge pull request #6 from isometry/feature/tcp-invert
Browse files Browse the repository at this point in the history
feat: add invert-mode to tcp provider to verify a port is closed
  • Loading branch information
isometry authored Apr 2, 2024
2 parents 611f50b + 310b9b6 commit f095a4d
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 17 deletions.
1 change: 1 addition & 0 deletions pkg/provider/tcp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ The TCP Provider is configured through the platform-health server's configuratio
* `name` (required): The name of the TCP service instance, used to identify the service in the health reports.
* `host` (required): The hostname or IP address of the TCP service to monitor.
* `port` (default: `80`): The port number of the TCP service to monitor.
* `invert` (default: `false`): Reverse logic to report "unhealthy" if port is open and "healthy" if it is closed.
* `timeout` (default: `1s`): The maximum time to wait for a connection to be established before timing out.

### Example
Expand Down
18 changes: 14 additions & 4 deletions pkg/provider/tcp/tcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type TCP struct {
Name string `mapstructure:"name"`
Host string `mapstructure:"host"`
Port int `mapstructure:"port" default:"80"`
Invert bool `mapstructure:"invert" default:"false"`
Timeout time.Duration `mapstructure:"timeout" default:"1s"`
}

Expand All @@ -33,6 +34,7 @@ func (i *TCP) LogValue() slog.Value {
slog.String("host", i.Host),
slog.Int("port", i.Port),
slog.Any("timeout", i.Timeout),
slog.Bool("invert", i.Invert),
}
return slog.GroupValue(logAttr...)
}
Expand Down Expand Up @@ -66,9 +68,17 @@ func (i *TCP) GetHealth(ctx context.Context) *ph.HealthCheckResponse {
dialer := &net.Dialer{}
conn, err := dialer.DialContext(ctx, "tcp", address)
if err != nil {
return component.Unhealthy(err.Error())
if i.Invert {
return component.Healthy()
} else {
return component.Unhealthy(err.Error())
}
} else {
_ = conn.Close()
if i.Invert {
return component.Unhealthy("port open")
} else {
return component.Healthy()
}
}
_ = conn.Close()

return component.Healthy()
}
50 changes: 37 additions & 13 deletions pkg/provider/tcp/tcp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,39 +25,63 @@ func TestTCP(t *testing.T) {
}
defer listener.Close()

port := listener.Addr().(*net.TCPAddr).Port

tests := []struct {
name string
port int
status ph.Status
name string
port int
invert bool
timeout time.Duration
expected ph.Status
}{
{
name: "Port open",
port: listener.Addr().(*net.TCPAddr).Port,
status: ph.Status_HEALTHY,
name: "Port open",
port: port,
expected: ph.Status_HEALTHY,
},
{
name: "Port closed",
port: 1,
expected: ph.Status_UNHEALTHY,
},
{
name: "Port closed, expect failure",
port: 1,
invert: true,
expected: ph.Status_HEALTHY,
},
{
name: "Unexpected timeout",
port: port,
timeout: time.Nanosecond,
expected: ph.Status_UNHEALTHY,
},
{
name: "Port closed",
port: 1,
status: ph.Status_UNHEALTHY,
name: "Expected timeout",
port: port,
invert: true,
timeout: time.Nanosecond,
expected: ph.Status_HEALTHY,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
instance := &tcp.TCP{
Name: "TestTCP",
Name: tt.name,
Host: "localhost",
Port: tt.port,
Timeout: time.Second,
Invert: tt.invert,
Timeout: tt.timeout,
}
instance.SetDefaults()

result := instance.GetHealth(context.Background())

assert.NotNil(t, result)
assert.Equal(t, tcp.TypeTCP, result.GetType())
assert.Equal(t, instance.Name, result.GetName())
assert.Equal(t, tt.status, result.GetStatus())
assert.Equal(t, tt.name, result.GetName())
assert.Equal(t, tt.expected, result.GetStatus())
})
}
}

0 comments on commit f095a4d

Please sign in to comment.