13 Commits

Author SHA1 Message Date
Mikolaj Pawlikowski
95363554e4 Merge pull request #124 from maxime1907/feat-config-zap
feat: support advanced zap configuration
2022-10-25 20:37:40 +01:00
Maxime Leroy
a913318ae3 feat: support advanced zap configuration
Signed-off-by: Maxime Leroy <19607336+maxime1907@users.noreply.github.com>
2022-10-25 12:30:35 +02:00
Mikolaj Pawlikowski
2f54105404 Merge pull request #121 from kitfoman/add-missing-dependency
[Bug Fix] add missing dependency
2022-08-29 16:55:12 +01:00
kitfoman
f6dbd2632b add missing dependency
Signed-off-by: kitfoman <thaddeusgetachew@gmail.com>
2022-08-29 10:41:39 -04:00
Mikolaj Pawlikowski
8ad0802439 Merge pull request #115 from kitfoman/add-external-probes
Extend DNS resolver to include TCP and HTTP checks for external targets
2022-08-26 21:05:02 +01:00
Tadewos Getachew
7cd571d15f Merge branch 'master' into add-external-probes 2022-05-08 22:06:35 -04:00
tgetachew
14ea96999a add external probes
Signed-off-by: kitfoman <thaddeusgetachew@gmail.com>

make timeout flags backwards compatible

Signed-off-by: kitfoman <thaddeusgetachew@gmail.com>
2022-05-08 22:02:09 -04:00
Tyler Lloyd
05ab610f10 cleanup IPv6 references
only check node IPs when determining hostIP

IP_VERSIONS not IP_FAMILIES

Signed-off-by: Tyler Lloyd <tyler.lloyd@microsoft.com>
2022-05-08 22:02:03 -04:00
Mikolaj Pawlikowski
1a9ae3a9ba Merge pull request #116 from tyler-lloyd/cleanup-ipv6
Cleanup ipv6
2022-04-15 14:09:45 +01:00
Mikolaj Pawlikowski
d976605bc6 Merge branch 'master' into cleanup-ipv6 2022-04-15 13:37:54 +01:00
Mikolaj Pawlikowski
5cc9bd55ad Merge pull request #119 from XIAOMI-CloudNative/feat/show-nodename
Fix pinger be removed by not found.
2022-04-15 13:36:46 +01:00
wanglijie6
72832bcbc4 Fix pinger be removed by not found.
heatmap will be broken in every refeshPeriod,
I found pinger is be deleted because of exists check faild.

updatePingers will check if a pod still exist or a new one,
and update pingers in every refreshPeriod.

the function exists failed to check pod exist, so fix it.

Signed-off-by: wanglijie6 <wanglijie6@xiaomi.com>
2022-04-15 19:14:53 +08:00
Tyler Lloyd
ef300d5ca2 cleanup IPv6 references
only check node IPs when determining hostIP

IP_VERSIONS not IP_FAMILIES

Signed-off-by: Tyler Lloyd <tyler.lloyd@microsoft.com>
2022-03-30 17:42:22 +00:00
33 changed files with 680 additions and 218 deletions

View File

@@ -23,6 +23,7 @@ RUN go mod vendor
FROM scratch as simple
COPY --from=builder /w/bin/goldpinger /goldpinger
COPY ./static /static
COPY ./config /config
ENTRYPOINT ["/goldpinger", "--static-file-path", "/static"]
# For vendor builds, use the simple build and add the vendor'd files

View File

@@ -1,5 +1,5 @@
name ?= goldpinger
version ?= v3.4.0
version ?= v3.7.0
bin ?= goldpinger
pkg ?= "github.com/bloomberg/goldpinger"
tag = $(name):$(version)

View File

@@ -231,7 +231,7 @@ You can also see [an example of using `kubeconfig` in the `./extras`](./extras/e
### Using with IPv4/IPv6 dual-stack
If your pods having IPv4 and IPv6 addresses assigned and you want to test communication over IPv6, you can specify the `USE_IPV6` environment variable which will use the IPv6 address on the pod and host.
If your cluster IPv4/IPv6 dual-stack and you want to force IPv6, you can set the `IP_VERSIONS` environment variable to "6" (default is "4") which will use the IPv6 address on the pod and host.
![ipv6](./extras/screenshot-ipv6.png)
@@ -256,6 +256,27 @@ and `goldpinger` should show something like this:
![screenshot-DNS-resolution](./extras/dns-screenshot.png)
### TCP and HTTP checks to external targets
Instances can also be configured to do simple TCP or HTTP checks on external targets. This is useful for visualizing more nuanced connectivity flows.
```sh
--tcp-targets= A list of external targets(<host>:<port> or <ip>:<port>) to attempt a TCP check on (space delimited) [$TCP_TARGETS]
--http-targets= A list of external targets(<http or https>://<url>) to attempt an HTTP{S} check on. A 200 HTTP code is considered successful. (space delimited) [$HTTP_TARGETS]
--tcp-targets-timeout= The timeout for a tcp check on the provided tcp-targets (default: 500) [$TCP_TARGETS_TIMEOUT]
--dns-targets-timeout= The timeout for a tcp check on the provided udp-targets (default: 500) [$DNS_TARGETS_TIMEOUT]
```
```yaml
- name: HTTP_TARGETS
value: http://bloomberg.com
- name: TCP_TARGETS
value: 10.34.5.141:5000 10.34.195.193:6442
```
the timeouts for the TCP, DNS and HTTP checks can be configured via `TCP_TARGETS_TIMEOUT`, `DNS_TARGETS_TIMEOUT` and `HTTP_TARGETS_TIMEOUT` respectively.
![screenshot-tcp-http-checks](./extras/tcp-checks-screenshot.png)
## Usage

View File

@@ -15,8 +15,12 @@
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"os"
"strconv"
"time"
"github.com/go-openapi/loads"
"go.uber.org/zap"
@@ -36,37 +40,32 @@ var (
Version, Build string
)
func getLogger() *zap.Logger {
func getLogger(zapconfigpath string) (*zap.Logger, error) {
var logger *zap.Logger
var err error
// We haven't parsed flags at this stage and that might be error prone
// so just use an envvar
if debug, err := strconv.ParseBool(os.Getenv("DEBUG")); err == nil && debug {
logger, err = zap.NewDevelopment()
} else {
logger, err = zap.NewProduction()
}
zapconfigJSON, err := ioutil.ReadFile(zapconfigpath)
if err != nil {
panic(err)
return nil, fmt.Errorf("Could not read zap config file: %w", err)
}
zap.ReplaceGlobals(logger)
return logger
var cfg zap.Config
if err := json.Unmarshal(zapconfigJSON, &cfg); err != nil {
return nil, fmt.Errorf("Could not read zap config as json: %w", err)
}
logger, err = cfg.Build()
if err != nil {
return nil, fmt.Errorf("Could not build zap config: %w", err)
}
return logger, nil
}
func main() {
logger := getLogger()
defer logger.Sync()
undo := zap.RedirectStdLog(logger)
defer undo()
logger.Info("Goldpinger", zap.String("version", Version), zap.String("build", Build))
// load embedded swagger file
swaggerSpec, err := loads.Analyzed(restapi.SwaggerJSON, "")
if err != nil {
logger.Error("Coud not parse swagger", zap.Error(err))
log.Fatalf("Could not parse swagger: %v", err)
}
// create new service API
@@ -83,7 +82,7 @@ func main() {
for _, optsGroup := range api.CommandLineOptionsGroups {
_, err := parser.AddGroup(optsGroup.ShortDescription, optsGroup.LongDescription, optsGroup.Options)
if err != nil {
logger.Error("Coud not add flag group", zap.Error(err))
log.Fatalf("Could not add flag group: %v", err)
}
}
@@ -97,6 +96,23 @@ func main() {
os.Exit(code)
}
// Configure logger
logger, err := getLogger(goldpinger.GoldpingerConfig.ZapConfigPath)
if err != nil {
var errDev error
logger, errDev = zap.NewDevelopment()
if errDev != nil {
log.Fatalf("Could not build a development logger: %v", errDev)
}
logger.Warn("Logger could not be built, defaulting to development settings", zap.String("error", fmt.Sprintf("%v", err)))
}
defer logger.Sync()
undo := zap.RedirectStdLog(logger)
defer undo()
logger.Info("Goldpinger", zap.String("version", Version), zap.String("build", Build))
if goldpinger.GoldpingerConfig.Namespace == nil {
goldpinger.GoldpingerConfig.Namespace = &goldpinger.PodNamespace
} else {
@@ -144,6 +160,23 @@ func main() {
logger.Error("Unknown IP version specified: expected values are 4 or 6", zap.Strings("IPVersions", goldpinger.GoldpingerConfig.IPVersions))
}
// Handle deprecated flags
if int(goldpinger.GoldpingerConfig.PingTimeout) == 0 {
logger.Warn("ping-timeout-ms is deprecated in favor of ping-timeout and will be removed in the future",
zap.Int64("ping-timeout-ms", goldpinger.GoldpingerConfig.PingTimeoutMs))
goldpinger.GoldpingerConfig.PingTimeout = time.Duration(goldpinger.GoldpingerConfig.PingTimeoutMs) * time.Millisecond
}
if int(goldpinger.GoldpingerConfig.CheckTimeout) == 0 {
logger.Warn("check-timeout-ms is deprecated in favor of check-timeout and will be removed in the future",
zap.Int64("check-timeout-ms", goldpinger.GoldpingerConfig.CheckTimeoutMs))
goldpinger.GoldpingerConfig.CheckTimeout = time.Duration(goldpinger.GoldpingerConfig.CheckTimeoutMs) * time.Millisecond
}
if int(goldpinger.GoldpingerConfig.CheckAllTimeout) == 0 {
logger.Warn("check-all-timeout-ms is deprecated in favor of check-all-timeout will be removed in the future",
zap.Int64("check-all-timeout-ms", goldpinger.GoldpingerConfig.CheckAllTimeoutMs))
goldpinger.GoldpingerConfig.CheckAllTimeout = time.Duration(goldpinger.GoldpingerConfig.CheckAllTimeoutMs) * time.Millisecond
}
server.ConfigureAPI()
goldpinger.StartUpdater()

21
config/zap.json Normal file
View File

@@ -0,0 +1,21 @@
{
"level": "info",
"encoding": "json",
"outputPaths": [
"stdout"
],
"errorOutputPaths": [
"stderr"
],
"initialFields": {
},
"encoderConfig": {
"messageKey": "message",
"levelKey": "level",
"levelEncoder": "lowercase",
"timeKey": "ts",
"timeEncoder": "ISO8601",
"callerKey": "caller",
"callerEncoder": "Short"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 576 KiB

2
go.mod
View File

@@ -5,7 +5,7 @@ go 1.15
require (
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 // indirect
github.com/cespare/xxhash v1.1.0
github.com/go-openapi/errors v0.20.0
github.com/go-openapi/errors v0.20.2
github.com/go-openapi/loads v0.19.5
github.com/go-openapi/runtime v0.19.26
github.com/go-openapi/spec v0.19.8

2
go.sum
View File

@@ -91,6 +91,8 @@ github.com/go-openapi/errors v0.19.6/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpX
github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
github.com/go-openapi/errors v0.20.0 h1:Sxpo9PjEHDzhs3FbnGNonvDgWcMW2U7wGTcDDSFSceM=
github.com/go-openapi/errors v0.20.0/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
github.com/go-openapi/errors v0.20.2 h1:dxy7PGTqEh94zj2E3h1cUmQQWiM1+aeCROfAr02EmK8=
github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=

View File

@@ -37,15 +37,12 @@ func CheckNeighbours(ctx context.Context) *models.CheckResults {
// Mux to prevent concurrent map address
checkResultsMux.Lock()
defer checkResultsMux.Unlock()
final := models.CheckResults{}
final.PodResults = make(map[string]models.PodResult)
for podName, podResult := range checkResults.PodResults {
final.PodResults[podName] = podResult
}
if len(GoldpingerConfig.DnsHosts) > 0 {
final.DNSResults = *checkDNS()
}
final.ProbeResults = checkTargets()
return &final
}
@@ -127,22 +124,58 @@ func pickPodHostIP(podIP, hostIP string) string {
return podIP
}
func checkDNS() *models.DNSResults {
results := models.DNSResults{}
for _, host := range GoldpingerConfig.DnsHosts {
var dnsResult models.DNSResult
start := time.Now()
_, err := net.LookupIP(host)
if err != nil {
dnsResult.Error = err.Error()
CountDnsError(host)
}
dnsResult.ResponseTimeMs = time.Since(start).Nanoseconds() / int64(time.Millisecond)
results[host] = dnsResult
func checkTargets() models.ProbeResults {
results := make(map[string][]models.ProbeResult)
probes := []struct {
protocol string
hosts []string
probeFn func(addr string, timeout time.Duration) error
statFn func(host string)
timeout time.Duration
}{
{
protocol: "dns",
hosts: GoldpingerConfig.DnsHosts,
probeFn: doDNSProbe,
statFn: CountDnsError,
timeout: GoldpingerConfig.DnsCheckTimeout,
},
{
protocol: "http",
hosts: GoldpingerConfig.HTTPTargets,
probeFn: doHTTPProbe,
statFn: CountHttpError,
timeout: GoldpingerConfig.HTTPCheckTimeout,
},
{
protocol: "tcp",
hosts: GoldpingerConfig.TCPTargets,
probeFn: doTCPProbe,
statFn: CountTcpError,
timeout: GoldpingerConfig.TCPCheckTimeout,
},
}
return &results
for _, probe := range probes {
for _, host := range probe.hosts {
if _, ok := results[host]; !ok {
results[host] = []models.ProbeResult{}
}
res := models.ProbeResult{Protocol: probe.protocol}
start := time.Now()
err := probe.probeFn(host, probe.timeout)
if err != nil {
res.Error = err.Error()
probe.statFn(host)
}
res.ResponseTimeMs = time.Since(start).Milliseconds()
results[host] = append(results[host], res)
}
}
return results
}
// CheckServicePodsResult results of the /check operation
@@ -195,7 +228,7 @@ func CheckAllPods(checkAllCtx context.Context, pods map[string]*GoldpingerPod) *
} else {
checkCtx, cancel := context.WithTimeout(
checkAllCtx,
time.Duration(GoldpingerConfig.CheckTimeoutMs)*time.Millisecond,
GoldpingerConfig.CheckTimeout,
)
defer cancel()
@@ -238,15 +271,15 @@ func CheckAllPods(checkAllCtx context.Context, pods map[string]*GoldpingerPod) *
PodIP: response.podIPv4,
})
if response.checkAllPodResult.Response != nil &&
response.checkAllPodResult.Response.DNSResults != nil {
if result.DNSResults == nil {
result.DNSResults = make(map[string]models.DNSResults)
response.checkAllPodResult.Response.ProbeResults != nil {
if result.ProbeResults == nil {
result.ProbeResults = make(map[string]models.ProbeResults)
}
for host := range response.checkAllPodResult.Response.DNSResults {
if result.DNSResults[host] == nil {
result.DNSResults[host] = make(map[string]models.DNSResult)
for host := range response.checkAllPodResult.Response.ProbeResults {
if result.ProbeResults[host] == nil {
result.ProbeResults[host] = make(map[string][]models.ProbeResult)
}
result.DNSResults[host][response.podName] = response.checkAllPodResult.Response.DNSResults[host]
result.ProbeResults[host][response.podName] = response.checkAllPodResult.Response.ProbeResults[host]
}
}
}

View File

@@ -15,12 +15,15 @@
package goldpinger
import (
"time"
"k8s.io/client-go/kubernetes"
)
// GoldpingerConfig represents the configuration for goldpinger
var GoldpingerConfig = struct {
StaticFilePath string `long:"static-file-path" description:"Folder for serving static files" env:"STATIC_FILE_PATH"`
ZapConfigPath string `long:"zap-config" description:"Path to zap config file" env:"ZAP_CONFIG" default:"/config/zap.json"`
KubeConfigPath string `long:"kubeconfig" description:"Path to kubeconfig file" env:"KUBECONFIG"`
RefreshInterval int `long:"refresh-interval" description:"If > 0, will create a thread and collect stats every n seconds" env:"REFRESH_INTERVAL" default:"30"`
JitterFactor float64 `long:"jitter-factor" description:"The amount of jitter to add while pinging clients" env:"JITTER_FACTOR" default:"0.05"`
@@ -35,12 +38,20 @@ var GoldpingerConfig = struct {
DisplayNodeName bool `long:"display-nodename" description:"Display nodename other than podname in UI (defaults is podname)." env:"DISPLAY_NODENAME"`
KubernetesClient *kubernetes.Clientset
DnsHosts []string `long:"host-to-resolve" description:"A host to attempt dns resolve on (space delimited)" env:"HOSTS_TO_RESOLVE" env-delim:" "`
DnsHosts []string `long:"host-to-resolve" description:"A host to attempt dns resolve on (space delimited)" env:"HOSTS_TO_RESOLVE" env-delim:" "`
TCPTargets []string `long:"tcp-targets" description:"A list of external targets(<host>:<port> or <ip>:<port>) to attempt a TCP check on (space delimited)" env:"TCP_TARGETS" env-delim:" "`
HTTPTargets []string `long:"http-targets" description:"A list of external targets(<http or https>://<url>) to attempt an HTTP{S} check on. A 200 HTTP code is considered successful.(space delimited)" env:"HTTP_TARGETS" env-delim:" "`
IPVersions []string `long:"ip-versions" description:"The IP versions to use (space delimited). Possible values are 4 and 6 (defaults to 4)." env:"IP_VERSIONS" env-delim:" "`
// Timeouts
PingTimeoutMs int64 `long:"ping-timeout-ms" description:"The timeout in milliseconds for a ping call to other goldpinger pods" env:"PING_TIMEOUT_MS" default:"300"`
CheckTimeoutMs int64 `long:"check-timeout-ms" description:"The timeout in milliseconds for a check call to other goldpinger pods" env:"CHECK_TIMEOUT_MS" default:"1000"`
CheckAllTimeoutMs int64 `long:"check-all-timeout-ms" description:"The timeout in milliseconds for a check-all call to other goldpinger pods" env:"CHECK_ALL_TIMEOUT_MS" default:"5000"`
PingTimeoutMs int64 `long:"ping-timeout-ms" description:"The timeout in milliseconds for a ping call to other goldpinger pods(deprecated)" env:"PING_TIMEOUT_MS" default:"300"`
CheckTimeoutMs int64 `long:"check-timeout-ms" description:"The timeout in milliseconds for a check call to other goldpinger pods(deprecated)" env:"CHECK_TIMEOUT_MS" default:"1000"`
CheckAllTimeoutMs int64 `long:"check-all-timeout-ms" description:"The timeout in milliseconds for a check-all call to other goldpinger pods(deprecated)" env:"CHECK_ALL_TIMEOUT_MS" default:"5000"`
PingTimeout time.Duration `long:"ping-timeout" description:"The timeout for a ping call to other goldpinger pods" env:"PING_TIMEOUT" default:"300ms"`
CheckTimeout time.Duration `long:"check-timeout" description:"The timeout for a check call to other goldpinger pods" env:"CHECK_TIMEOUT" default:"1000ms"`
CheckAllTimeout time.Duration `long:"check-all-timeout" description:"The timeout for a check-all call to other goldpinger pods" env:"CHECK_ALL_TIMEOUT" default:"5000ms"`
TCPCheckTimeout time.Duration `long:"tcp-targets-timeout" description:"The timeout for a tcp check on the provided tcp-targets" env:"TCP_TARGETS_TIMEOUT" default:"500ms"`
DnsCheckTimeout time.Duration `long:"dns-targets-timeout" description:"The timeout for a dns check on the provided dns-targets" env:"DNS_TARGETS_TIMEOUT" default:"500ms"`
HTTPCheckTimeout time.Duration `long:"http-targets-timeout" description:"The timeout for a http check on the provided http-targets" env:"HTTP_TARGETS_TIMEOUT" default:"500ms"`
}{}

View File

@@ -26,7 +26,6 @@ import (
"net/http"
"sort"
"strconv"
"time"
"go.uber.org/zap"
"golang.org/x/image/font"
@@ -83,7 +82,7 @@ func HeatmapHandler(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(
r.Context(),
time.Duration(GoldpingerConfig.CheckAllTimeoutMs)*time.Millisecond,
GoldpingerConfig.CheckAllTimeout,
)
defer cancel()

View File

@@ -69,7 +69,8 @@ func getHostIP(p v1.Pod) string {
var hostIP string
for _, addr := range node.Status.Addresses {
if ipMatchesConfig(addr.Address) {
if (addr.Type == v1.NodeInternalIP || addr.Type == v1.NodeExternalIP) &&
ipMatchesConfig(addr.Address) {
hostIP = addr.Address
}
}

View File

@@ -46,7 +46,7 @@ type Pinger struct {
func NewPinger(pod *GoldpingerPod, resultsChan chan<- PingAllPodsResult) *Pinger {
p := Pinger{
pod: pod,
timeout: time.Duration(GoldpingerConfig.PingTimeoutMs) * time.Millisecond,
timeout: GoldpingerConfig.PingTimeout,
resultsChan: resultsChan,
stopChan: make(chan struct{}),

72
pkg/goldpinger/probes.go Normal file
View File

@@ -0,0 +1,72 @@
// Copyright 2018 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package goldpinger
import (
"context"
"crypto/tls"
"fmt"
"net"
"net/http"
"net/url"
"time"
)
func doDNSProbe(addr string, timeout time.Duration) error {
resolver := net.Resolver{}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
ips, err := resolver.LookupHost(ctx, addr)
if len(ips) == 0 {
return fmt.Errorf("%s was resolved to 0 ips", addr)
}
return err
}
func doTCPProbe(addr string, timeout time.Duration) error {
conn, err := net.DialTimeout("tcp", addr, timeout)
if conn != nil {
defer conn.Close()
}
return err
}
func doHTTPProbe(addr string, timeout time.Duration) error {
client := http.Client{Timeout: timeout}
u, err := url.Parse(addr)
if err != nil {
return err
}
if u.Scheme != "http" && u.Scheme != "https" {
return fmt.Errorf("invalid url scheme: '%s' in address", u.Scheme)
}
if u.Scheme == "https" {
client.Transport = &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
}
}
resp, err := client.Get(addr)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return fmt.Errorf("%s returned non-200 resp: %d", addr, resp.StatusCode)
}
return err
}

View File

@@ -103,7 +103,26 @@ var (
"host",
},
)
goldPingerTcpErrorsCounter = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "goldpinger_tcp_errors_total",
Help: "Statistics of TCP probe errors per instance",
},
[]string{
"goldpinger_instance",
"host",
},
)
goldPingerHttpErrorsCounter = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "goldpinger_http_errors_total",
Help: "Statistics of HTTP probe errors per instance",
},
[]string{
"goldpinger_instance",
"host",
},
)
bootTime = time.Now()
)
@@ -115,6 +134,8 @@ func init() {
prometheus.MustRegister(goldpingerResponseTimeKubernetesHistogram)
prometheus.MustRegister(goldpingerErrorsCounter)
prometheus.MustRegister(goldpingerDnsErrorsCounter)
prometheus.MustRegister(goldPingerHttpErrorsCounter)
prometheus.MustRegister(goldPingerTcpErrorsCounter)
zap.L().Info("Metrics setup - see /metrics")
}
@@ -173,6 +194,22 @@ func CountDnsError(host string) {
).Inc()
}
// CountTcpError counts instances of tcp errors for prober
func CountTcpError(host string) {
goldPingerTcpErrorsCounter.WithLabelValues(
GoldpingerConfig.Hostname,
host,
).Inc()
}
// CountHttpError counts instances of tcp errors for prober
func CountHttpError(host string) {
goldPingerHttpErrorsCounter.WithLabelValues(
GoldpingerConfig.Hostname,
host,
).Inc()
}
// returns a timer for easy observing of the durations of calls to kubernetes API
func GetLabeledKubernetesCallsTimer() *prometheus.Timer {
return prometheus.NewTimer(

View File

@@ -34,8 +34,8 @@ var checkResultsMux = sync.Mutex{}
// - there is already a pinger with the same name
// - the pinger has the same podIP
// - the pinger has the same hostIP
func exists(existingPods map[string]*GoldpingerPod, new *GoldpingerPod) bool {
old, exists := existingPods[new.Name]
func exists(existingPods map[string]*GoldpingerPod, podName string, new *GoldpingerPod) bool {
old, exists := existingPods[podName]
return exists && (old.PodIP == new.PodIP) && (old.HostIP == new.HostIP)
}
@@ -61,7 +61,7 @@ func updatePingers(resultsChan chan<- PingAllPodsResult) {
latest := SelectPods()
for podName, pod := range latest {
if exists(existingPods, pod) {
if exists(existingPods, podName, pod) {
// This pod continues to exist in the latest iteration of the update
// without any changes
// Delete it from the set of pods that we wish to delete
@@ -153,14 +153,17 @@ func updateCounters() {
}
}
CountHealthyUnhealthyNodes(counterHealthy, float64(len(checkResults.PodResults))-counterHealthy)
// check DNS, but don't block the access to checkResultsMux
// check external targets, don't block the access to checkResultsMux
nodesHealthy := int(counterHealthy) == len(checkResults.PodResults)
go func(healthySoFar bool) {
if healthySoFar {
for _, response := range *checkDNS() {
if response.Error != "" {
healthySoFar = false
break
probeResults := checkTargets()
for host := range probeResults {
for _, response := range probeResults[host] {
if response.Error != "" {
healthySoFar = false
break
}
}
}
}

View File

@@ -95,6 +95,8 @@ func (m *CheckAllPodResult) validateResponse(formats strfmt.Registry) error {
if err := m.Response.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("response")
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("response")
}
return err
}
@@ -123,6 +125,8 @@ func (m *CheckAllPodResult) contextValidateResponse(ctx context.Context, formats
if err := m.Response.ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("response")
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("response")
}
return err
}

View File

@@ -23,9 +23,6 @@ type CheckAllResults struct {
// o k
OK *bool `json:"OK,omitempty"`
// dns results
DNSResults map[string]DNSResults `json:"dnsResults,omitempty"`
// hosts
Hosts []*CheckAllResultsHostsItems0 `json:"hosts"`
@@ -35,6 +32,9 @@ type CheckAllResults struct {
// hosts number
HostsNumber int32 `json:"hosts-number,omitempty"`
// probe results
ProbeResults map[string]ProbeResults `json:"probeResults,omitempty"`
// responses
Responses map[string]CheckAllPodResult `json:"responses,omitempty"`
}
@@ -43,11 +43,11 @@ type CheckAllResults struct {
func (m *CheckAllResults) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateDNSResults(formats); err != nil {
if err := m.validateHosts(formats); err != nil {
res = append(res, err)
}
if err := m.validateHosts(formats); err != nil {
if err := m.validateProbeResults(formats); err != nil {
res = append(res, err)
}
@@ -61,24 +61,6 @@ func (m *CheckAllResults) Validate(formats strfmt.Registry) error {
return nil
}
func (m *CheckAllResults) validateDNSResults(formats strfmt.Registry) error {
if swag.IsZero(m.DNSResults) { // not required
return nil
}
for k := range m.DNSResults {
if val, ok := m.DNSResults[k]; ok {
if err := val.Validate(formats); err != nil {
return err
}
}
}
return nil
}
func (m *CheckAllResults) validateHosts(formats strfmt.Registry) error {
if swag.IsZero(m.Hosts) { // not required
return nil
@@ -93,6 +75,8 @@ func (m *CheckAllResults) validateHosts(formats strfmt.Registry) error {
if err := m.Hosts[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("hosts" + "." + strconv.Itoa(i))
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("hosts" + "." + strconv.Itoa(i))
}
return err
}
@@ -103,6 +87,24 @@ func (m *CheckAllResults) validateHosts(formats strfmt.Registry) error {
return nil
}
func (m *CheckAllResults) validateProbeResults(formats strfmt.Registry) error {
if swag.IsZero(m.ProbeResults) { // not required
return nil
}
for k := range m.ProbeResults {
if val, ok := m.ProbeResults[k]; ok {
if err := val.Validate(formats); err != nil {
return err
}
}
}
return nil
}
func (m *CheckAllResults) validateResponses(formats strfmt.Registry) error {
if swag.IsZero(m.Responses) { // not required
return nil
@@ -115,6 +117,11 @@ func (m *CheckAllResults) validateResponses(formats strfmt.Registry) error {
}
if val, ok := m.Responses[k]; ok {
if err := val.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("responses" + "." + k)
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("responses" + "." + k)
}
return err
}
}
@@ -128,11 +135,11 @@ func (m *CheckAllResults) validateResponses(formats strfmt.Registry) error {
func (m *CheckAllResults) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
var res []error
if err := m.contextValidateDNSResults(ctx, formats); err != nil {
if err := m.contextValidateHosts(ctx, formats); err != nil {
res = append(res, err)
}
if err := m.contextValidateHosts(ctx, formats); err != nil {
if err := m.contextValidateProbeResults(ctx, formats); err != nil {
res = append(res, err)
}
@@ -146,12 +153,17 @@ func (m *CheckAllResults) ContextValidate(ctx context.Context, formats strfmt.Re
return nil
}
func (m *CheckAllResults) contextValidateDNSResults(ctx context.Context, formats strfmt.Registry) error {
func (m *CheckAllResults) contextValidateHosts(ctx context.Context, formats strfmt.Registry) error {
for k := range m.DNSResults {
for i := 0; i < len(m.Hosts); i++ {
if val, ok := m.DNSResults[k]; ok {
if err := val.ContextValidate(ctx, formats); err != nil {
if m.Hosts[i] != nil {
if err := m.Hosts[i].ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("hosts" + "." + strconv.Itoa(i))
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("hosts" + "." + strconv.Itoa(i))
}
return err
}
}
@@ -161,15 +173,12 @@ func (m *CheckAllResults) contextValidateDNSResults(ctx context.Context, formats
return nil
}
func (m *CheckAllResults) contextValidateHosts(ctx context.Context, formats strfmt.Registry) error {
func (m *CheckAllResults) contextValidateProbeResults(ctx context.Context, formats strfmt.Registry) error {
for i := 0; i < len(m.Hosts); i++ {
for k := range m.ProbeResults {
if m.Hosts[i] != nil {
if err := m.Hosts[i].ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("hosts" + "." + strconv.Itoa(i))
}
if val, ok := m.ProbeResults[k]; ok {
if err := val.ContextValidate(ctx, formats); err != nil {
return err
}
}

View File

@@ -19,22 +19,22 @@ import (
// swagger:model CheckResults
type CheckResults struct {
// dns results
DNSResults DNSResults `json:"dnsResults,omitempty"`
// pod results
PodResults map[string]PodResult `json:"podResults,omitempty"`
// probe results
ProbeResults ProbeResults `json:"probeResults,omitempty"`
}
// Validate validates this check results
func (m *CheckResults) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateDNSResults(formats); err != nil {
if err := m.validatePodResults(formats); err != nil {
res = append(res, err)
}
if err := m.validatePodResults(formats); err != nil {
if err := m.validateProbeResults(formats); err != nil {
res = append(res, err)
}
@@ -44,23 +44,6 @@ func (m *CheckResults) Validate(formats strfmt.Registry) error {
return nil
}
func (m *CheckResults) validateDNSResults(formats strfmt.Registry) error {
if swag.IsZero(m.DNSResults) { // not required
return nil
}
if m.DNSResults != nil {
if err := m.DNSResults.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("dnsResults")
}
return err
}
}
return nil
}
func (m *CheckResults) validatePodResults(formats strfmt.Registry) error {
if swag.IsZero(m.PodResults) { // not required
return nil
@@ -73,6 +56,11 @@ func (m *CheckResults) validatePodResults(formats strfmt.Registry) error {
}
if val, ok := m.PodResults[k]; ok {
if err := val.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("podResults" + "." + k)
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("podResults" + "." + k)
}
return err
}
}
@@ -82,15 +70,34 @@ func (m *CheckResults) validatePodResults(formats strfmt.Registry) error {
return nil
}
func (m *CheckResults) validateProbeResults(formats strfmt.Registry) error {
if swag.IsZero(m.ProbeResults) { // not required
return nil
}
if m.ProbeResults != nil {
if err := m.ProbeResults.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("probeResults")
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("probeResults")
}
return err
}
}
return nil
}
// ContextValidate validate this check results based on the context it is used
func (m *CheckResults) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
var res []error
if err := m.contextValidateDNSResults(ctx, formats); err != nil {
if err := m.contextValidatePodResults(ctx, formats); err != nil {
res = append(res, err)
}
if err := m.contextValidatePodResults(ctx, formats); err != nil {
if err := m.contextValidateProbeResults(ctx, formats); err != nil {
res = append(res, err)
}
@@ -100,18 +107,6 @@ func (m *CheckResults) ContextValidate(ctx context.Context, formats strfmt.Regis
return nil
}
func (m *CheckResults) contextValidateDNSResults(ctx context.Context, formats strfmt.Registry) error {
if err := m.DNSResults.ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("dnsResults")
}
return err
}
return nil
}
func (m *CheckResults) contextValidatePodResults(ctx context.Context, formats strfmt.Registry) error {
for k := range m.PodResults {
@@ -127,6 +122,20 @@ func (m *CheckResults) contextValidatePodResults(ctx context.Context, formats st
return nil
}
func (m *CheckResults) contextValidateProbeResults(ctx context.Context, formats strfmt.Registry) error {
if err := m.ProbeResults.ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("probeResults")
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("probeResults")
}
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *CheckResults) MarshalBinary() ([]byte, error) {
if m == nil {

View File

@@ -66,6 +66,8 @@ func (m *PingResults) validateReceived(formats strfmt.Registry) error {
if err := m.Received.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("received")
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("received")
}
return err
}
@@ -94,6 +96,8 @@ func (m *PingResults) contextValidateReceived(ctx context.Context, formats strfm
if err := m.Received.ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("received")
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("received")
}
return err
}

View File

@@ -118,6 +118,8 @@ func (m *PodResult) validateResponse(formats strfmt.Registry) error {
if err := m.Response.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("response")
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("response")
}
return err
}
@@ -146,6 +148,8 @@ func (m *PodResult) contextValidateResponse(ctx context.Context, formats strfmt.
if err := m.Response.ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("response")
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("response")
}
return err
}

View File

@@ -0,0 +1,56 @@
// Code generated by go-swagger; DO NOT EDIT.
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// ProbeResult probe result
//
// swagger:model ProbeResult
type ProbeResult struct {
// error
Error string `json:"error,omitempty"`
// protocol
Protocol string `json:"protocol,omitempty"`
// response time ms
ResponseTimeMs int64 `json:"response-time-ms,omitempty"`
}
// Validate validates this probe result
func (m *ProbeResult) Validate(formats strfmt.Registry) error {
return nil
}
// ContextValidate validates this probe result based on context it is used
func (m *ProbeResult) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *ProbeResult) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *ProbeResult) UnmarshalBinary(b []byte) error {
var res ProbeResult
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -0,0 +1,78 @@
// Code generated by go-swagger; DO NOT EDIT.
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"strconv"
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/validate"
)
// ProbeResults probe results
//
// swagger:model ProbeResults
type ProbeResults map[string][]ProbeResult
// Validate validates this probe results
func (m ProbeResults) Validate(formats strfmt.Registry) error {
var res []error
for k := range m {
if err := validate.Required(k, "body", m[k]); err != nil {
return err
}
for i := 0; i < len(m[k]); i++ {
if err := m[k][i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName(k + "." + strconv.Itoa(i))
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName(k + "." + strconv.Itoa(i))
}
return err
}
}
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
// ContextValidate validate this probe results based on the context it is used
func (m ProbeResults) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
var res []error
for k := range m {
for i := 0; i < len(m[k]); i++ {
if err := m[k][i].ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName(k + "." + strconv.Itoa(i))
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName(k + "." + strconv.Itoa(i))
}
return err
}
}
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View File

@@ -20,7 +20,6 @@ import (
"context"
"crypto/tls"
"net/http"
"time"
"strings"
@@ -61,7 +60,7 @@ func configureAPI(api *operations.GoldpingerAPI) http.Handler {
ctx, cancel := context.WithTimeout(
params.HTTPRequest.Context(),
time.Duration(goldpinger.GoldpingerConfig.PingTimeoutMs)*time.Millisecond,
goldpinger.GoldpingerConfig.PingTimeout,
)
defer cancel()
@@ -74,7 +73,7 @@ func configureAPI(api *operations.GoldpingerAPI) http.Handler {
ctx, cancel := context.WithTimeout(
params.HTTPRequest.Context(),
time.Duration(goldpinger.GoldpingerConfig.CheckTimeoutMs)*time.Millisecond,
goldpinger.GoldpingerConfig.CheckTimeout,
)
defer cancel()
@@ -87,7 +86,7 @@ func configureAPI(api *operations.GoldpingerAPI) http.Handler {
ctx, cancel := context.WithTimeout(
params.HTTPRequest.Context(),
time.Duration(goldpinger.GoldpingerConfig.CheckAllTimeoutMs)*time.Millisecond,
goldpinger.GoldpingerConfig.CheckAllTimeout,
)
defer cancel()
@@ -100,7 +99,7 @@ func configureAPI(api *operations.GoldpingerAPI) http.Handler {
ctx, cancel := context.WithTimeout(
params.HTTPRequest.Context(),
time.Duration(goldpinger.GoldpingerConfig.CheckAllTimeoutMs)*time.Millisecond,
goldpinger.GoldpingerConfig.CheckAllTimeout,
)
defer cancel()

View File

@@ -203,11 +203,23 @@ func init() {
"type": "integer",
"format": "int32"
},
"httpResults": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/HttpResults"
}
},
"responses": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/CheckAllPodResult"
}
},
"tcpResults": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/TcpResults"
}
}
}
},
@@ -217,11 +229,17 @@ func init() {
"dnsResults": {
"$ref": "#/definitions/DnsResults"
},
"httpResults": {
"$ref": "#/definitions/HttpResults"
},
"podResults": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/PodResult"
}
},
"tcpResults": {
"$ref": "#/definitions/TcpResults"
}
}
},
@@ -261,21 +279,10 @@ func init() {
}
}
},
"DnsResult": {
"properties": {
"error": {
"type": "string"
},
"response-time-ms": {
"type": "number",
"format": "int64"
}
}
},
"DnsResults": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/DnsResult"
"$ref": "#/definitions/ProbeResult"
}
},
"HealthCheckResults": {
@@ -295,6 +302,12 @@ func init() {
}
}
},
"HttpResults": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/ProbeResult"
}
},
"PingResults": {
"type": "object",
"properties": {
@@ -342,6 +355,23 @@ func init() {
"format": "int32"
}
}
},
"ProbeResult": {
"properties": {
"error": {
"type": "string"
},
"response-time-ms": {
"type": "number",
"format": "int64"
}
}
},
"TcpResults": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/ProbeResult"
}
}
}
}`))
@@ -518,11 +548,23 @@ func init() {
"type": "integer",
"format": "int32"
},
"httpResults": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/HttpResults"
}
},
"responses": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/CheckAllPodResult"
}
},
"tcpResults": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/TcpResults"
}
}
}
},
@@ -548,11 +590,17 @@ func init() {
"dnsResults": {
"$ref": "#/definitions/DnsResults"
},
"httpResults": {
"$ref": "#/definitions/HttpResults"
},
"podResults": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/PodResult"
}
},
"tcpResults": {
"$ref": "#/definitions/TcpResults"
}
}
},
@@ -592,21 +640,10 @@ func init() {
}
}
},
"DnsResult": {
"properties": {
"error": {
"type": "string"
},
"response-time-ms": {
"type": "number",
"format": "int64"
}
}
},
"DnsResults": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/DnsResult"
"$ref": "#/definitions/ProbeResult"
}
},
"HealthCheckResults": {
@@ -626,6 +663,12 @@ func init() {
}
}
},
"HttpResults": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/ProbeResult"
}
},
"PingResults": {
"type": "object",
"properties": {
@@ -673,6 +716,23 @@ func init() {
"format": "int32"
}
}
},
"ProbeResult": {
"properties": {
"error": {
"type": "string"
},
"response-time-ms": {
"type": "number",
"format": "int64"
}
}
},
"TcpResults": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/ProbeResult"
}
}
}
}`))

View File

@@ -42,7 +42,7 @@ type CheckAllPods struct {
func (o *CheckAllPods) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
route, rCtx, _ := o.Context.RouteInfo(r)
if rCtx != nil {
r = rCtx
*r = *rCtx
}
var Params = NewCheckAllPodsParams()
if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params

View File

@@ -42,7 +42,7 @@ type CheckServicePods struct {
func (o *CheckServicePods) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
route, rCtx, _ := o.Context.RouteInfo(r)
if rCtx != nil {
r = rCtx
*r = *rCtx
}
var Params = NewCheckServicePodsParams()
if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params

View File

@@ -42,7 +42,7 @@ type ClusterHealth struct {
func (o *ClusterHealth) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
route, rCtx, _ := o.Context.RouteInfo(r)
if rCtx != nil {
r = rCtx
*r = *rCtx
}
var Params = NewClusterHealthParams()
if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params

View File

@@ -42,7 +42,7 @@ type Healthz struct {
func (o *Healthz) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
route, rCtx, _ := o.Context.RouteInfo(r)
if rCtx != nil {
r = rCtx
*r = *rCtx
}
var Params = NewHealthzParams()
if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params

View File

@@ -42,7 +42,7 @@ type Ping struct {
func (o *Ping) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
route, rCtx, _ := o.Context.RouteInfo(r)
if rCtx != nil {
r = rCtx
*r = *rCtx
}
var Params = NewPingParams()
if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params

View File

@@ -305,9 +305,6 @@ func (s *Server) Serve() (err error) {
s.Fatalf("no certificate was configured for TLS")
}
// must have at least one certificate or panics
httpsServer.TLSConfig.BuildNameToCertificate()
configureServer(httpsServer, "https", s.httpsServerL.Addr().String())
servers = append(servers, httpsServer)

View File

@@ -213,6 +213,7 @@ var loadingDialog = function(enable){
var global_data = undefined;
var s; // the sigma graph
var main = function(timeout){
timeout = timeout || Number($("#timeout").val()) || 5.0;
@@ -229,7 +230,6 @@ var main = function(timeout){
// prepare nodes
var nodes = [];
var dnsCheckNodes = [];
var podIPs = [];
var resp = data.responses;
for (let podIP in resp) {
@@ -284,39 +284,44 @@ var main = function(timeout){
})
})
console.log(nodes);
if ('dnsResults' in data) {
var yoffset = 0;
for (let checkedHost in data.dnsResults) {
let value = data.dnsResults[checkedHost];
var allOk = true;
for (let pod in value) {
var podData = value[pod];
var elapsed = 0;
if ('response-time-ms' in podData) {
elapsed = podData['response-time-ms'];
}
var podOk = (!('error' in podData));
allOk = allOk && podOk
edges.push({
source: pod,
target: checkedHost,
_data: {
var probeResultsNodes = [];
if ('probeResults' in data) {
var yoffset = 0;
for (let checkedHost in data.probeResults) {
let value = data.probeResults[checkedHost];
var allOk = true;
for (let pod in value) {
for (var i = 0; i < value[pod].length; i++){
var elapsed = 0;
var podData = value[pod][i];
if ('response-time-ms' in podData) {
elapsed = podData['response-time-ms'];
}
var podOk = (!('error' in podData));
allOk = allOk && podOk
edges.push({
source: pod,
target: checkedHost,
_data: {
"OK": podOk,
"elapsed": elapsed,
"isDNSCheckNode": true,
}
});
"isprobeResultsNode": true,
}
});
}
}
value["OK"] = allOk
dnsCheckNodes.push({
"label": checkedHost,
"id": checkedHost,
"x": 0,
"y": 0,
_data: value,
});
}
probeResultsNodes.push({
"label": checkedHost,
"id": checkedHost,
"x": 0,
"y": 0,
_data: value,
});
}
}
// build the actual graph
@@ -351,7 +356,7 @@ var main = function(timeout){
});
// generate any dns nodes on the graph
dnsCheckNodes.forEach(function(node, i, a){
probeResultsNodes.forEach(function(node, i, a){
node.x = 2;
node.y = (0.6 * i / a.length) - 0.8;
node.size = 10;
@@ -359,7 +364,6 @@ var main = function(timeout){
if (!node._data.OK) {
node.color = "red";
}
//console.log(node);
s.graph.addNode(node);
});
@@ -374,7 +378,7 @@ var main = function(timeout){
if (!edge._data.OK) {
color = "red";
}
if ("isDNSCheckNode" in edge._data) {
if ("isprobeResultsNode" in edge._data) {
type = "dashed";
}
var edge = {

View File

@@ -12,17 +12,21 @@ definitions:
type: integer
ping:
type: integer
DnsResult:
ProbeResult:
properties:
response-time-ms:
type: number
format: int64
error:
type: string
DnsResults:
protocol:
type: string
ProbeResults:
type: object
additionalProperties:
$ref: '#/definitions/DnsResult'
type: array
items:
$ref: '#/definitions/ProbeResult'
PingResults:
type: object
properties:
@@ -60,8 +64,8 @@ definitions:
CheckResults:
type: object
properties:
dnsResults:
$ref: '#/definitions/DnsResults'
probeResults:
$ref: '#/definitions/ProbeResults'
podResults:
type: object
additionalProperties:
@@ -110,10 +114,10 @@ definitions:
podIP:
type: string
format: ipv4
dnsResults:
probeResults:
type: object
additionalProperties:
$ref: '#/definitions/DnsResults'
$ref: '#/definitions/ProbeResults'
responses:
type: object
additionalProperties: