66 Commits

Author SHA1 Message Date
Mikolaj Pawlikowski
a77ad0c3c1 Merge pull request #83 from skamboj/calm-the-thundering-herd
Calm the thundering herd
2020-04-08 13:31:46 +01:00
Sachin Kamboj
7e60ee675a Simplify updateCounters, don't try to maintain a running count
Signed-off-by: Sachin Kamboj <skamboj1@bloomberg.net>
2020-04-08 07:56:04 -04:00
Sachin Kamboj
d68d35bbab Add a ping time that gives the last time a node was pinged
Signed-off-by: Sachin Kamboj <skamboj1@bloomberg.net>
2020-04-07 21:04:43 -04:00
Sachin Kamboj
2a78a9cec5 Don't ping all pods on call, return existing data
Signed-off-by: Sachin Kamboj <skamboj1@bloomberg.net>
2020-04-07 20:49:01 -04:00
Sachin Kamboj
9db241d67d Update the set of pingers at regular intervals from the k8s API server
Signed-off-by: Sachin Kamboj <skamboj1@bloomberg.net>
2020-04-07 19:54:19 -04:00
Sachin Kamboj
bc313a7fbb Merge branch 'master' into calm-the-thundering-herd 2020-04-07 14:18:09 -04:00
Mikolaj Pawlikowski
1a5d07b162 Merge pull request #82 from skamboj/better-logging
Better logging
2020-04-07 17:54:38 +01:00
Mikolaj Pawlikowski
131ea12745 Merge pull request #81 from skamboj/customize-timeouts
Customize timeouts
2020-04-07 14:40:22 +01:00
Sachin Kamboj
40f57b1a4e Get rid of the lock and keep a running count of healthy/unhealthy nodes
Signed-off-by: Sachin Kamboj <skamboj1@bloomberg.net>
2020-04-07 08:45:14 -04:00
Mikolaj Pawlikowski
d5dd96a419 Merge pull request #79 from skamboj/pod-name-instead-of-pod-ip
Pod name instead of pod ip
2020-04-07 13:38:21 +01:00
Sachin Kamboj
8a40aee927 Have the updater continuously ping pods and collate the results
Signed-off-by: Sachin Kamboj <skamboj1@bloomberg.net>
2020-04-07 08:02:36 -04:00
Sachin Kamboj
0690ac21a2 Command line options for adding a jitter-factor
Signed-off-by: Sachin Kamboj <skamboj1@bloomberg.net>
2020-04-07 07:55:48 -04:00
Sachin Kamboj
d0dfd3e493 Add code to continuously ping the pods and send the results over a channel
Signed-off-by: Sachin Kamboj <skamboj1@bloomberg.net>
2020-04-07 07:54:10 -04:00
Sachin Kamboj
cd5316bbb9 Allow debug logging
Signed-off-by: Sachin Kamboj <skamboj1@bloomberg.net>
2020-04-06 22:50:17 -04:00
Sachin Kamboj
9ae3e78035 Better structured logging
Signed-off-by: Sachin Kamboj <skamboj1@bloomberg.net>
2020-04-06 22:39:57 -04:00
Sachin Kamboj
2e1c799a25 Replace log statements with zap
Signed-off-by: Sachin Kamboj <skamboj1@bloomberg.net>
2020-04-06 22:18:04 -04:00
Sachin Kamboj
d33d6d6636 Update dependencies
Signed-off-by: Sachin Kamboj <skamboj1@bloomberg.net>
2020-04-06 22:17:24 -04:00
Sachin Kamboj
4a7a53603f Configure zap in main to do our logging
Signed-off-by: Sachin Kamboj <skamboj1@bloomberg.net>
2020-04-06 22:16:20 -04:00
Sachin Kamboj
e3942bd5eb Fix the crashing UI
Signed-off-by: Sachin Kamboj <skamboj1@bloomberg.net>
2020-04-06 20:33:25 -04:00
Sachin Kamboj
1c6362b2a9 Add a context to the ping results
Signed-off-by: Sachin Kamboj <skamboj1@bloomberg.net>
2020-04-06 19:43:22 -04:00
Sachin Kamboj
7bbdcacf9b Add a context/timeout to the heatmap
Signed-off-by: Sachin Kamboj <skamboj1@bloomberg.net>
2020-04-06 19:42:59 -04:00
Sachin Kamboj
3a6ab53ced Add a context to the updater
Signed-off-by: Sachin Kamboj <skamboj1@bloomberg.net>
2020-04-06 19:41:43 -04:00
Sachin Kamboj
aa7eaca30e Get the context from the request and add overall timeouts
Signed-off-by: Sachin Kamboj <skamboj1@bloomberg.net>
2020-04-06 19:38:32 -04:00
Sachin Kamboj
86f9f8a1dd Add a context and timeout to the ping and check calls
Signed-off-by: Sachin Kamboj <skamboj1@bloomberg.net>
2020-04-06 19:36:14 -04:00
Sachin Kamboj
c8fbf618c7 Add flags for custom timeouts for the three operations
Signed-off-by: Sachin Kamboj <skamboj1@bloomberg.net>
2020-04-06 19:32:47 -04:00
Sachin Kamboj
1338f28163 Increment the major version since this is a breaking change
Signed-off-by: Sachin Kamboj <skamboj1@bloomberg.net>
2020-04-03 23:31:05 -04:00
Sachin Kamboj
f0c66f29c7 Store results by pod name instead of pod IP
Signed-off-by: Sachin Kamboj <skamboj1@bloomberg.net>
2020-04-03 23:22:52 -04:00
Sachin Kamboj
86febf8295 Update the way of selecting pods
Signed-off-by: Sachin Kamboj <skamboj1@bloomberg.net>
2020-04-03 23:17:26 -04:00
Sachin Kamboj
aa789fdea8 Add a PodName to the config
Signed-off-by: Sachin Kamboj <skamboj1@bloomberg.net>
2020-04-03 23:16:43 -04:00
Sachin Kamboj
a95279ac8e Also remove the PodSelector from the config and main
Signed-off-by: Sachin Kamboj <skamboj1@bloomberg.net>
2020-04-03 23:13:53 -04:00
Sachin Kamboj
6ee538549a Simplify and remove the PodSelecter struct
There is currently only a single way to select pods to ping and there is really no way to conifgure alternatives. So this commit removes the struct and simplifes the code.

Signed-off-by: Sachin Kamboj <skamboj1@bloomberg.net>
2020-04-03 23:11:53 -04:00
Sachin Kamboj
7fa3138235 Also store the PodName when fetching from k8s API server. Also map from podName to GoldpingerPod sruct
Signed-off-by: Sachin Kamboj <skamboj1@bloomberg.net>
2020-04-03 23:10:36 -04:00
Sachin Kamboj
00cd1e3886 Auto-generated code with the changes to the swagger
Signed-off-by: Sachin Kamboj <skamboj1@bloomberg.net>
2020-04-03 23:09:05 -04:00
Sachin Kamboj
4152784d21 Add a PodIP to the results now that we are using PodName as a key
Signed-off-by: Sachin Kamboj <skamboj1@bloomberg.net>
2020-04-03 23:00:48 -04:00
Mikolaj Pawlikowski
c66050e536 Merge pull request #78 from skamboj/migrate-to-go-modules
Migrate to go modules
2020-04-02 20:40:46 +01:00
Mikolaj Pawlikowski
34d84b233c Merge branch 'master' into migrate-to-go-modules 2020-04-02 17:56:00 +01:00
Mikolaj Pawlikowski
e07ae6a64c Merge pull request #75 from ifooth/master
fix prometheus ruler expr
2020-04-02 17:55:47 +01:00
Mikolaj Pawlikowski
6844a8d2b4 Merge branch 'master' into master 2020-04-02 17:36:43 +01:00
Sachin Kamboj
c23112de50 Update the CI
Signed-off-by: Sachin Kamboj <skamboj1@bloomberg.net>
2020-04-01 21:06:01 -04:00
Sachin Kamboj
436c1a7243 Update the README to remove references to dep
Signed-off-by: Sachin Kamboj <skamboj1@bloomberg.net>
2020-04-01 21:00:31 -04:00
Sachin Kamboj
66c8dc0cce Update the version/tag to be compatible with what go expects
Signed-off-by: Sachin Kamboj <skamboj1@bloomberg.net>
2020-04-01 20:53:45 -04:00
Sachin Kamboj
8a7e5a36ba Update the multistage build to use go 1.14 and go modules; Remove dep
Signed-off-by: Sachin Kamboj <skamboj1@bloomberg.net>
2020-04-01 20:26:03 -04:00
Sachin Kamboj
4e508cb8c8 Update the vendoring
Signed-off-by: Sachin Kamboj <skamboj1@bloomberg.net>
2020-04-01 20:17:37 -04:00
Sachin Kamboj
536a7ffbbb Remove the dep files
Signed-Off-By: Sachin Kamboj <skamboj1@bloomberg.net>
2020-04-01 20:16:47 -04:00
Sachin Kamboj
bf25a51c3e Add a go.mod and go.sum
Signed-Off-By: Sachin Kamboj <skamboj1@bloomberg.net>
2020-04-01 19:48:15 -04:00
Mikolaj Pawlikowski
02b38e3ab7 Merge pull request #77 from sandeepmendiratta/sandeep-heatmap_fix
minor typo correction in heat map page. Also updated version and Read…
2020-03-22 21:36:49 +00:00
Sandeep Mendiratta
0870833cf5 minor typo correction in heat map page. Also updated version and Readme with new version
Signed-off-by: Sandeep Mendiratta <smendiratta@yahoo.com>
2020-03-22 16:28:22 -05:00
Mikolaj Pawlikowski
d5400d6e2e Merge pull request #76 from seeker89/fix-empty-ips
Fix a Goldpinger reporting healthy when kubernetes returns an empty IP field
2020-03-11 14:21:05 +00:00
Mikolaj Pawlikowski
94d4a7c81e Use HostIP as podIP, if the there is no podIP
Signed-off-by: Mikolaj Pawlikowski <mikolaj@pawlikowski.pl>
2020-03-11 13:25:12 +00:00
Mikolaj Pawlikowski
94dc18c9c2 Update the version in README
Signed-off-by: Mikolaj Pawlikowski <mikolaj@pawlikowski.pl>
2020-03-11 13:05:22 +00:00
Mikolaj Pawlikowski
8964cab729 Bump patch version
Signed-off-by: Mikolaj Pawlikowski <mikolaj@pawlikowski.pl>
2020-03-11 13:05:22 +00:00
Mikolaj Pawlikowski
d297e2f3c6 Change CheckAllPods to return an error when can't create a server
Signed-off-by: Mikolaj Pawlikowski <mikolaj@pawlikowski.pl>
2020-03-11 13:05:22 +00:00
Mikolaj Pawlikowski
02067f03ab Change PingAllPods to send an error if the client can't be created
Signed-off-by: Mikolaj Pawlikowski <mikolaj@pawlikowski.pl>
2020-03-11 13:05:22 +00:00
Mikolaj Pawlikowski
b96cab34ea Change the client builder to fail, if the IP provided is empty, instead of defaulting to localhost
Signed-off-by: Mikolaj Pawlikowski <mikolaj@pawlikowski.pl>
2020-03-11 13:05:22 +00:00
Mikolaj Pawlikowski
bc7afb7a17 Return response time on failure to ping
Signed-off-by: Mikolaj Pawlikowski <mikolaj@pawlikowski.pl>
2020-03-11 13:05:22 +00:00
Mikolaj Pawlikowski
89a6c76c9c Formatting
Signed-off-by: Mikolaj Pawlikowski <mikolaj@pawlikowski.pl>
2020-03-11 13:05:22 +00:00
Joe Lei
60436daf18 fix prometheus ruler expr
Signed-off-by: Joe Lei <thezero12@hotmail.com>
2020-02-18 10:59:43 +08:00
Mikolaj Pawlikowski
618369f540 Merge pull request #71 from SuleimanWA/master
prometheus service auto-discovery
2019-11-26 20:13:58 +00:00
suleimanWA
1ab777c3d5 Merge branch 'master' of github.com:SuleimanWA/goldpinger
move scrap annotation from service to pod level

Signed-off-by: suleimanWA <suleiman-94@hotmail.com>
2019-11-26 20:52:46 +02:00
suleiman abualrob
6315c71a2c Update README.md
Kubernetes master node by most of default installation are taint, so goldPinger DaemonSet will not deployed to master, in order to make it run on master nodes also, you have to tolerate the taint

Signed-off-by: suleimanWA <suleiman-94@hotmail.com>
2019-11-26 20:42:27 +02:00
suleiman abualrob
49a47284b6 Update README.md
Kubernetes master node by most of default installation are taint, so goldPinger DaemonSet will not deployed to master, in order to make it run on master nodes also, you have to tolerate the taint

Signed-off-by: suleimanWA <suleiman-94@hotmail.com>
2019-11-26 20:38:52 +02:00
suleiman abualrob
ec2155878a Update README.md
If you have Prometheus in your environment, adding these annotation will let  Prometheus auto-discovery fetch your metrics automatically from service-name:port/metrics

Signed-off-by: suleimanWA <suleiman-94@hotmail.com>
2019-11-26 19:03:14 +02:00
Mikolaj Pawlikowski
cab268b725 Merge pull request #70 from angelbarrera92/secure-k8s-deployment
Secure k8s deployment
2019-11-14 16:53:06 +00:00
Ángel Barrera Sánchez
e552b236a0 Change documentation example
Signed-off-by: Ángel Barrera Sánchez <angel@sighup.io>
2019-11-14 17:19:42 +01:00
Ángel Barrera Sánchez
8a86a74478 Change dashboard's datasource parameter to be variable
Signed-off-by: Ángel Barrera Sánchez <angel@sighup.io>
2019-11-14 17:19:42 +01:00
Ángel Barrera Sánchez
4dab241ff6 Change daemonset definition to be more secure
Signed-off-by: Ángel Barrera Sánchez <angel@sighup.io>
2019-11-14 17:19:42 +01:00
54 changed files with 1295 additions and 1205 deletions

View File

@@ -4,22 +4,20 @@ services:
- docker
go:
- "1.10.x"
- "1.14.x"
- master
script:
- docker --version
# dep
- go get -u github.com/golang/dep/cmd/dep
# build locally and run locally
- make clean && make vendor && make && ./bin/goldpinger --help
# build an image and run the image
- make clean && make vendor && make build
- docker images
- docker run `make version` --help
# build an image using the multistage builder
- make clean && make build-multistage
- docker images
@@ -36,5 +34,5 @@ deploy:
skip_cleanup: true
on:
tags: true
go: "1.10.x"
go: "1.14.x"
condition: -n "$DOCKER_PASSWORD"

View File

@@ -1,15 +1,14 @@
FROM golang:1.11-alpine as builder
FROM golang:1.14-alpine as builder
# Install our build tools
RUN apk add --update git make bash
RUN go get -u github.com/golang/dep/cmd/dep
# Get dependencies
WORKDIR /go/src/github.com/bloomberg/goldpinger
COPY Gopkg.toml Gopkg.lock Makefile ./
RUN make vendor
WORKDIR /w
COPY go.mod go.sum /w/
RUN go mod download
# Build goldpinger
@@ -19,6 +18,6 @@ RUN make bin/goldpinger
# Build the asset container, copy over goldpinger
FROM scratch
COPY --from=builder /go/src/github.com/bloomberg/goldpinger/bin/goldpinger /goldpinger
COPY --from=builder /w/bin/goldpinger /goldpinger
COPY ./static /static
ENTRYPOINT ["/goldpinger", "--static-file-path", "/static"]
ENTRYPOINT ["/goldpinger", "--static-file-path", "/static"]

670
Gopkg.lock generated
View File

@@ -1,670 +0,0 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
digest = "1:d1665c44bd5db19aaee18d1b6233c99b0b9a986e8bccb24ef54747547a48027f"
name = "github.com/PuerkitoBio/purell"
packages = ["."]
pruneopts = "UT"
revision = "0bcb03f4b4d0a9428594752bd2a3b9aa0a9d4bd4"
version = "v1.1.0"
[[projects]]
branch = "master"
digest = "1:c739832d67eb1e9cc478a19cc1a1ccd78df0397bf8a32978b759152e205f644b"
name = "github.com/PuerkitoBio/urlesc"
packages = ["."]
pruneopts = "UT"
revision = "de5bf2ad457846296e2031421a34e2568e304e35"
[[projects]]
digest = "1:320e7ead93de9fd2b0e59b50fd92a4d50c1f8ab455d96bc2eb083267453a9709"
name = "github.com/asaskevich/govalidator"
packages = ["."]
pruneopts = "UT"
revision = "ccb8e960c48f04d6935e72476ae4a51028f9e22f"
version = "v9"
[[projects]]
branch = "master"
digest = "1:d6afaeed1502aa28e80a4ed0981d570ad91b2579193404256ce672ed0a609e0d"
name = "github.com/beorn7/perks"
packages = ["quantile"]
pruneopts = "UT"
revision = "3a771d992973f24aa725d07868b467d1ddfceafb"
[[projects]]
digest = "1:998cf998358a303ac2430c386ba3fd3398477d6013153d3c6e11432765cc9ae6"
name = "github.com/cespare/xxhash"
packages = ["."]
pruneopts = "UT"
revision = "3b82fb7d186719faeedd0c2864f868c74fbf79a1"
version = "v2.0.0"
[[projects]]
digest = "1:6f82cacd0af5921e99bf3f46748705239b36489464f4529a1589bc895764fb18"
name = "github.com/docker/go-units"
packages = ["."]
pruneopts = "UT"
revision = "47565b4f722fb6ceae66b95f853feed578a4a51c"
version = "v0.3.3"
[[projects]]
digest = "1:c45cef8e0074ea2f8176a051df38553ba997a3616f1ec2d35222b1cf9864881e"
name = "github.com/ghodss/yaml"
packages = ["."]
pruneopts = "UT"
revision = "73d445a93680fa1a78ae23a5839bad48f32ba1ee"
[[projects]]
branch = "master"
digest = "1:7fb51688eadf38272411852d7a2b3538c7caff53309abee6c0964a83c00fe69e"
name = "github.com/globalsign/mgo"
packages = [
"bson",
"internal/json",
]
pruneopts = "UT"
revision = "eeefdecb41b842af6dc652aaea4026e8403e62df"
[[projects]]
digest = "1:c49164b7b1e34324258ae61deef2cba7912005ba9cb7a9ee4930fe6bdfec7b5d"
name = "github.com/go-openapi/analysis"
packages = [
".",
"internal",
]
pruneopts = "UT"
revision = "c701774f4e604d952e4e8c56dee260be696e33c3"
version = "v0.17.2"
[[projects]]
digest = "1:ac4b35a4bba11edb2110fca0707bae03ae92fbd8222e6b483465d98efaabfb97"
name = "github.com/go-openapi/errors"
packages = ["."]
pruneopts = "UT"
revision = "d9664f9fab8994271e573ed69cf2adfc09b7a800"
version = "v0.17.2"
[[projects]]
digest = "1:953a2628e4c5c72856b53f5470ed5e071c55eccf943d798d42908102af2a610f"
name = "github.com/go-openapi/jsonpointer"
packages = ["."]
pruneopts = "UT"
revision = "ef5f0afec364d3b9396b7b77b43dbe26bf1f8004"
version = "v0.17.2"
[[projects]]
digest = "1:81210e0af657a0fb3638932ec68e645236bceefa4c839823db0c4d918f080895"
name = "github.com/go-openapi/jsonreference"
packages = ["."]
pruneopts = "UT"
revision = "8483a886a90412cd6858df4ea3483dce9c8e35a3"
version = "v0.17.2"
[[projects]]
digest = "1:a20e8bf0e58e2010677432ffbe5533c1e83bdf368ba5b057f3e00e2071ca8b09"
name = "github.com/go-openapi/loads"
packages = ["."]
pruneopts = "UT"
revision = "150d36912387ec2f607be674c5be309ddccc0eed"
version = "v0.17.2"
[[projects]]
digest = "1:76b781f51e08cc0494b4abacf70d4b9da0a4732e270b7f2045ca9f0f875ad6d1"
name = "github.com/go-openapi/runtime"
packages = [
".",
"client",
"flagext",
"logger",
"middleware",
"middleware/denco",
"middleware/header",
"middleware/untyped",
"security",
]
pruneopts = "UT"
revision = "231d7876b7019dbcbfc97a7ba764379497b67c1d"
version = "v0.17.2"
[[projects]]
digest = "1:394fed5c0425fe01da3a34078adaa1682e4deaea6e5d232dde25c4034004c151"
name = "github.com/go-openapi/spec"
packages = ["."]
pruneopts = "UT"
revision = "5bae59e25b21498baea7f9d46e9c147ec106a42e"
version = "v0.17.2"
[[projects]]
digest = "1:ffa79f4705a3a85f2412d2d163c37acdf60d128c679e641c323a5de712e23d27"
name = "github.com/go-openapi/strfmt"
packages = ["."]
pruneopts = "UT"
revision = "edab9990ffc9b4a428f3306ecf4d18a069ca3317"
version = "v0.17.2"
[[projects]]
digest = "1:32f3d2e7f343de7263c550d696fb8a64d3c49d8df16b1ddfc8e80e1e4b3233ce"
name = "github.com/go-openapi/swag"
packages = ["."]
pruneopts = "UT"
revision = "5899d5c5e619fda5fa86e14795a835f473ca284c"
version = "v0.17.2"
[[projects]]
digest = "1:58541fddf3f4ec485710f1b346e7f647baf09a878a604e47e3668c600fe44076"
name = "github.com/go-openapi/validate"
packages = ["."]
pruneopts = "UT"
revision = "d2eab7d93009e9215fc85b2faa2c2f2a98c2af48"
version = "v0.17.2"
[[projects]]
digest = "1:f83d740263b44fdeef3e1bce6147b5d7283fcad1a693d39639be33993ecf3db1"
name = "github.com/gogo/protobuf"
packages = [
"proto",
"sortkeys",
]
pruneopts = "UT"
revision = "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
[[projects]]
digest = "1:2edd2416f89b4e841df0e4a78802ce14d2bc7ad79eba1a45986e39f0f8cb7d87"
name = "github.com/golang/glog"
packages = ["."]
pruneopts = "UT"
revision = "44145f04b68cf362d9c4df2182967c2275eaefed"
[[projects]]
digest = "1:4c0989ca0bcd10799064318923b9bc2db6b4d6338dd75f3f2d86c3511aaaf5cf"
name = "github.com/golang/protobuf"
packages = [
"proto",
"ptypes",
"ptypes/any",
"ptypes/duration",
"ptypes/timestamp",
]
pruneopts = "UT"
revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5"
version = "v1.2.0"
[[projects]]
branch = "master"
digest = "1:0bfbe13936953a98ae3cfe8ed6670d396ad81edf069a806d2f6515d7bb6950df"
name = "github.com/google/btree"
packages = ["."]
pruneopts = "UT"
revision = "4030bb1f1f0c35b30ca7009e9ebd06849dd45306"
[[projects]]
digest = "1:41bfd4219241b7f7d6e6fdb13fc712576f1337e68e6b895136283b76928fdd66"
name = "github.com/google/gofuzz"
packages = ["."]
pruneopts = "UT"
revision = "44d81051d367757e1c7c6a5a86423ece9afcf63c"
[[projects]]
digest = "1:75eb87381d25cc75212f52358df9c3a2719584eaa9685cd510ce28699122f39d"
name = "github.com/googleapis/gnostic"
packages = [
"OpenAPIv2",
"compiler",
"extensions",
]
pruneopts = "UT"
revision = "0c5108395e2debce0d731cf0287ddf7242066aba"
[[projects]]
digest = "1:878f0defa9b853f9acfaf4a162ba450a89d0050eff084f9fe7f5bd15948f172a"
name = "github.com/gregjones/httpcache"
packages = [
".",
"diskcache",
]
pruneopts = "UT"
revision = "787624de3eb7bd915c329cba748687a3b22666a6"
[[projects]]
digest = "1:3e260afa138eab6492b531a3b3d10ab4cb70512d423faa78b8949dec76e66a21"
name = "github.com/imdario/mergo"
packages = ["."]
pruneopts = "UT"
revision = "9316a62528ac99aaecb4e47eadd6dc8aa6533d58"
version = "v0.3.5"
[[projects]]
digest = "1:a2cff208d4759f6ba1b1cd228587b0a1869f95f22542ec9cd17fff64430113c7"
name = "github.com/jessevdk/go-flags"
packages = ["."]
pruneopts = "UT"
revision = "c6ca198ec95c841fdb89fc0de7496fed11ab854e"
version = "v1.4.0"
[[projects]]
digest = "1:bb3cc4c1b21ea18cfa4e3e47440fc74d316ab25b0cf42927e8c1274917bd9891"
name = "github.com/json-iterator/go"
packages = ["."]
pruneopts = "UT"
revision = "f2b4162afba35581b6d4a50d3b8f34e33c144682"
[[projects]]
branch = "master"
digest = "1:84a5a2b67486d5d67060ac393aa255d05d24ed5ee41daecd5635ec22657b6492"
name = "github.com/mailru/easyjson"
packages = [
"buffer",
"jlexer",
"jwriter",
]
pruneopts = "UT"
revision = "60711f1a8329503b04e1c88535f419d0bb440bff"
[[projects]]
digest = "1:ff5ebae34cfbf047d505ee150de27e60570e8c394b3b8fdbb720ff6ac71985fc"
name = "github.com/matttproud/golang_protobuf_extensions"
packages = ["pbutil"]
pruneopts = "UT"
revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c"
version = "v1.0.1"
[[projects]]
digest = "1:53bc4cd4914cd7cd52139990d5170d6dc99067ae31c56530621b18b35fc30318"
name = "github.com/mitchellh/mapstructure"
packages = ["."]
pruneopts = "UT"
revision = "3536a929edddb9a5b34bd6861dc4a9647cb459fe"
version = "v1.1.2"
[[projects]]
digest = "1:33422d238f147d247752996a26574ac48dcf472976eda7f5134015f06bf16563"
name = "github.com/modern-go/concurrent"
packages = ["."]
pruneopts = "UT"
revision = "bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94"
version = "1.0.3"
[[projects]]
digest = "1:e32bdbdb7c377a07a9a46378290059822efdce5c8d96fe71940d87cb4f918855"
name = "github.com/modern-go/reflect2"
packages = ["."]
pruneopts = "UT"
revision = "4b7aa43c6742a2c18fdef89dd197aaae7dac7ccd"
version = "1.0.1"
[[projects]]
branch = "master"
digest = "1:3bf17a6e6eaa6ad24152148a631d18662f7212e21637c2699bff3369b7f00fa2"
name = "github.com/petar/GoLLRB"
packages = ["llrb"]
pruneopts = "UT"
revision = "53be0d36a84c2a886ca057d34b6aa4468df9ccb4"
[[projects]]
digest = "1:0e7775ebbcf00d8dd28ac663614af924411c868dca3d5aa762af0fae3808d852"
name = "github.com/peterbourgon/diskv"
packages = ["."]
pruneopts = "UT"
revision = "5f041e8faa004a95c88a202771f4cc3e991971e6"
version = "v2.0.1"
[[projects]]
digest = "1:26663fafdea73a38075b07e8e9d82fc0056379d2be8bb4e13899e8fda7c7dd23"
name = "github.com/prometheus/client_golang"
packages = [
"prometheus",
"prometheus/internal",
"prometheus/promhttp",
]
pruneopts = "UT"
revision = "abad2d1bd44235a26707c172eab6bca5bf2dbad3"
version = "v0.9.1"
[[projects]]
branch = "master"
digest = "1:2d5cd61daa5565187e1d96bae64dbbc6080dacf741448e9629c64fd93203b0d4"
name = "github.com/prometheus/client_model"
packages = ["go"]
pruneopts = "UT"
revision = "5c3871d89910bfb32f5fcab2aa4b9ec68e65a99f"
[[projects]]
branch = "master"
digest = "1:db712fde5d12d6cdbdf14b777f0c230f4ff5ab0be8e35b239fc319953ed577a4"
name = "github.com/prometheus/common"
packages = [
"expfmt",
"internal/bitbucket.org/ww/goautoneg",
"model",
]
pruneopts = "UT"
revision = "7e9e6cabbd393fc208072eedef99188d0ce788b6"
[[projects]]
branch = "master"
digest = "1:ef74914912f99c79434d9c09658274678bc85080ebe3ab32bec3940ebce5e1fc"
name = "github.com/prometheus/procfs"
packages = [
".",
"internal/util",
"nfs",
"xfs",
]
pruneopts = "UT"
revision = "185b4288413d2a0dd0806f78c90dde719829e5ae"
[[projects]]
digest = "1:9424f440bba8f7508b69414634aef3b2b3a877e522d8a4624692412805407bb7"
name = "github.com/spf13/pflag"
packages = ["."]
pruneopts = "UT"
revision = "583c0c0531f06d5278b7d917446061adc344b5cd"
version = "v1.0.1"
[[projects]]
digest = "1:2731ee5852c26a3585f70d1a6cff8422383b98bad405eb6611cd4a2334be1df6"
name = "github.com/stuartnelson3/go-rendezvous"
packages = ["."]
pruneopts = "UT"
revision = "16dc0292e5f420d89a7dc4319775a1e5e461dc01"
version = "v0.2.0"
[[projects]]
digest = "1:3f3a05ae0b95893d90b9b3b5afdb79a9b3d96e4e36e099d841ae602e4aca0da8"
name = "golang.org/x/crypto"
packages = ["ssh/terminal"]
pruneopts = "UT"
revision = "de0752318171da717af4ce24d0a2e8626afaeb11"
[[projects]]
branch = "master"
digest = "1:09c175055d303dadf3f82513c66e6da0b95ba22bc8e5d267a2674d16d95ea77a"
name = "golang.org/x/image"
packages = [
"font",
"font/basicfont",
"font/plan9font",
"math/fixed",
]
pruneopts = "UT"
revision = "31aff87c08e9a5e5d524279a564f96968336f886"
[[projects]]
branch = "master"
digest = "1:eb8583d4582ffbc5c6d3ec00132cd0835101edde42b6f24eaafa628d1596f881"
name = "golang.org/x/net"
packages = [
"context",
"http/httpguts",
"http2",
"http2/hpack",
"idna",
"netutil",
]
pruneopts = "UT"
revision = "10aee181995363b41f712a55844a0dd52ea04646"
[[projects]]
digest = "1:9359217acc6040b4be710ce34473acef28023ad39bfafecea34ffaea7f1e1890"
name = "golang.org/x/oauth2"
packages = [
".",
"internal",
]
pruneopts = "UT"
revision = "a6bd8cefa1811bd24b86f8902872e4e8225f74c4"
[[projects]]
branch = "master"
digest = "1:509feef845f6af582cb82caad5eb176016b30714facdc754d84869ca31305b59"
name = "golang.org/x/sys"
packages = [
"unix",
"windows",
]
pruneopts = "UT"
revision = "7155702f2d47d94b134229da97195d0130cab001"
[[projects]]
digest = "1:0c56024909189aee3364b7f21a95a27459f718aa7c199a5c111c36cfffd9eaef"
name = "golang.org/x/text"
packages = [
"collate",
"collate/build",
"internal/colltab",
"internal/gen",
"internal/tag",
"internal/triegen",
"internal/ucd",
"language",
"secure/bidirule",
"transform",
"unicode/bidi",
"unicode/cldr",
"unicode/norm",
"unicode/rangetable",
"width",
]
pruneopts = "UT"
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
version = "v0.3.0"
[[projects]]
digest = "1:d37b0ef2944431fe9e8ef35c6fffc8990d9e2ca300588df94a6890f3649ae365"
name = "golang.org/x/time"
packages = ["rate"]
pruneopts = "UT"
revision = "f51c12702a4d776e4c1fa9b0fabab841babae631"
[[projects]]
digest = "1:08206298775e5b462e6c0333f4471b44e63f1a70e42952b6ede4ecc9572281eb"
name = "google.golang.org/appengine"
packages = [
"internal",
"internal/base",
"internal/datastore",
"internal/log",
"internal/remote_api",
"internal/urlfetch",
"urlfetch",
]
pruneopts = "UT"
revision = "4a4468ece617fc8205e99368fa2200e9d1fad421"
version = "v1.3.0"
[[projects]]
digest = "1:ef72505cf098abdd34efeea032103377bec06abb61d8a06f002d5d296a4b1185"
name = "gopkg.in/inf.v0"
packages = ["."]
pruneopts = "UT"
revision = "3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4"
version = "v0.9.0"
[[projects]]
digest = "1:342378ac4dcb378a5448dd723f0784ae519383532f5e70ade24132c4c8693202"
name = "gopkg.in/yaml.v2"
packages = ["."]
pruneopts = "UT"
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
version = "v2.2.1"
[[projects]]
digest = "1:910ec974550174f4ca48b9f4a3caec16b693e584c3762dc726dc0dcf28f8e318"
name = "k8s.io/api"
packages = [
"admissionregistration/v1alpha1",
"admissionregistration/v1beta1",
"apps/v1",
"apps/v1beta1",
"apps/v1beta2",
"authentication/v1",
"authentication/v1beta1",
"authorization/v1",
"authorization/v1beta1",
"autoscaling/v1",
"autoscaling/v2beta1",
"autoscaling/v2beta2",
"batch/v1",
"batch/v1beta1",
"batch/v2alpha1",
"certificates/v1beta1",
"coordination/v1beta1",
"core/v1",
"events/v1beta1",
"extensions/v1beta1",
"networking/v1",
"policy/v1beta1",
"rbac/v1",
"rbac/v1alpha1",
"rbac/v1beta1",
"scheduling/v1alpha1",
"scheduling/v1beta1",
"settings/v1alpha1",
"storage/v1",
"storage/v1alpha1",
"storage/v1beta1",
]
pruneopts = "UT"
revision = "fd83cbc87e7632ccd8bbab63d2b673d4e0c631cc"
version = "kubernetes-1.12.0"
[[projects]]
digest = "1:18f352651d6e8578fdbaf29c68334b042439b288b8ae4112c2b2ba9a6e35ced0"
name = "k8s.io/apimachinery"
packages = [
"pkg/api/errors",
"pkg/api/meta",
"pkg/api/resource",
"pkg/apis/meta/v1",
"pkg/apis/meta/v1/unstructured",
"pkg/apis/meta/v1beta1",
"pkg/conversion",
"pkg/conversion/queryparams",
"pkg/fields",
"pkg/labels",
"pkg/runtime",
"pkg/runtime/schema",
"pkg/runtime/serializer",
"pkg/runtime/serializer/json",
"pkg/runtime/serializer/protobuf",
"pkg/runtime/serializer/recognizer",
"pkg/runtime/serializer/streaming",
"pkg/runtime/serializer/versioning",
"pkg/selection",
"pkg/types",
"pkg/util/clock",
"pkg/util/errors",
"pkg/util/framer",
"pkg/util/intstr",
"pkg/util/json",
"pkg/util/naming",
"pkg/util/net",
"pkg/util/runtime",
"pkg/util/sets",
"pkg/util/validation",
"pkg/util/validation/field",
"pkg/util/yaml",
"pkg/version",
"pkg/watch",
"third_party/forked/golang/reflect",
]
pruneopts = "UT"
revision = "6dd46049f39503a1fc8d65de4bd566829e95faff"
version = "kubernetes-1.12.0"
[[projects]]
digest = "1:51fd9ac9f2be10d79f5af101a7a1d758ef283fdb028a0d11198754bd3d4a6020"
name = "k8s.io/client-go"
packages = [
"discovery",
"kubernetes",
"kubernetes/scheme",
"kubernetes/typed/admissionregistration/v1alpha1",
"kubernetes/typed/admissionregistration/v1beta1",
"kubernetes/typed/apps/v1",
"kubernetes/typed/apps/v1beta1",
"kubernetes/typed/apps/v1beta2",
"kubernetes/typed/authentication/v1",
"kubernetes/typed/authentication/v1beta1",
"kubernetes/typed/authorization/v1",
"kubernetes/typed/authorization/v1beta1",
"kubernetes/typed/autoscaling/v1",
"kubernetes/typed/autoscaling/v2beta1",
"kubernetes/typed/autoscaling/v2beta2",
"kubernetes/typed/batch/v1",
"kubernetes/typed/batch/v1beta1",
"kubernetes/typed/batch/v2alpha1",
"kubernetes/typed/certificates/v1beta1",
"kubernetes/typed/coordination/v1beta1",
"kubernetes/typed/core/v1",
"kubernetes/typed/events/v1beta1",
"kubernetes/typed/extensions/v1beta1",
"kubernetes/typed/networking/v1",
"kubernetes/typed/policy/v1beta1",
"kubernetes/typed/rbac/v1",
"kubernetes/typed/rbac/v1alpha1",
"kubernetes/typed/rbac/v1beta1",
"kubernetes/typed/scheduling/v1alpha1",
"kubernetes/typed/scheduling/v1beta1",
"kubernetes/typed/settings/v1alpha1",
"kubernetes/typed/storage/v1",
"kubernetes/typed/storage/v1alpha1",
"kubernetes/typed/storage/v1beta1",
"pkg/apis/clientauthentication",
"pkg/apis/clientauthentication/v1alpha1",
"pkg/apis/clientauthentication/v1beta1",
"pkg/version",
"plugin/pkg/client/auth/exec",
"rest",
"rest/watch",
"tools/auth",
"tools/clientcmd",
"tools/clientcmd/api",
"tools/clientcmd/api/latest",
"tools/clientcmd/api/v1",
"tools/metrics",
"tools/reference",
"transport",
"util/cert",
"util/connrotation",
"util/flowcontrol",
"util/homedir",
"util/integer",
]
pruneopts = "UT"
revision = "1638f8970cefaa404ff3a62950f88b08292b2696"
version = "v9.0.0"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
input-imports = [
"github.com/cespare/xxhash",
"github.com/go-openapi/errors",
"github.com/go-openapi/loads",
"github.com/go-openapi/runtime",
"github.com/go-openapi/runtime/client",
"github.com/go-openapi/runtime/flagext",
"github.com/go-openapi/runtime/middleware",
"github.com/go-openapi/runtime/security",
"github.com/go-openapi/spec",
"github.com/go-openapi/strfmt",
"github.com/go-openapi/swag",
"github.com/go-openapi/validate",
"github.com/jessevdk/go-flags",
"github.com/prometheus/client_golang/prometheus",
"github.com/prometheus/client_golang/prometheus/promhttp",
"github.com/stuartnelson3/go-rendezvous",
"golang.org/x/image/font",
"golang.org/x/image/font/basicfont",
"golang.org/x/image/math/fixed",
"golang.org/x/net/netutil",
"k8s.io/apimachinery/pkg/apis/meta/v1",
"k8s.io/client-go/kubernetes",
"k8s.io/client-go/rest",
"k8s.io/client-go/tools/clientcmd",
]
solver-name = "gps-cdcl"
solver-version = 1

View File

@@ -1,82 +0,0 @@
# Gopkg.toml example
#
# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
#
# [prune]
# non-go = false
# go-tests = true
# unused-packages = true
[[constraint]]
name = "github.com/go-openapi/errors"
version = "0.17.2"
[[constraint]]
name = "github.com/go-openapi/loads"
version = "0.17.2"
[[constraint]]
name = "github.com/go-openapi/runtime"
version = "0.17.2"
[[constraint]]
name = "github.com/go-openapi/spec"
version = "0.17.2"
[[constraint]]
name = "github.com/go-openapi/strfmt"
version = "0.17.2"
[[constraint]]
name = "github.com/go-openapi/swag"
version = "0.17.2"
[[constraint]]
name = "github.com/go-openapi/validate"
version = "0.17.2"
[[constraint]]
name = "github.com/jessevdk/go-flags"
version = "1.4.0"
[[constraint]]
name = "github.com/prometheus/client_golang"
version = "0.9.1"
[[constraint]]
branch = "master"
name = "golang.org/x/net"
[[constraint]]
name = "k8s.io/apimachinery"
version = "kubernetes-1.12.0"
[[constraint]]
name = "k8s.io/client-go"
version = "9.0.0"
[[constraint]]
name = "github.com/stuartnelson3/go-rendezvous"
version = "0.2.0"
[prune]
go-tests = true
unused-packages = true

View File

@@ -1,5 +1,5 @@
name ?= goldpinger
version ?= 2.0.0
version ?= v3.0.0
bin ?= goldpinger
pkg ?= "github.com/bloomberg/goldpinger"
tag = $(name):$(version)
@@ -17,8 +17,9 @@ clean:
vendor:
rm -rf ./vendor
dep ensure -v -vendor-only
go mod vendor
# Download the latest swagger releases from: https://github.com/go-swagger/go-swagger/releases/
swagger:
swagger generate server -t pkg -f ./swagger.yml --exclude-main -A goldpinger && \
swagger generate client -t pkg -f ./swagger.yml -A goldpinger

View File

@@ -10,23 +10,25 @@ Oh, and it gives you the graph below for your cluster. Check out the [video expl
## On the menu
- [Rationale](#rationale)
- [Quick start](#quick-start)
- [Building](#building)
- [Compiling using a multi-stage Dockerfile](#compiling-using-a-multi-stage-dockerfile)
- [Compiling locally](#compiling-locally)
- [Installation](#installation)
- [Authentication with Kubernetes API](#authentication-with-kubernetes-api)
- [Example YAML](#example-yaml)
- [Note on DNS](#note-on-dns)
- [Usage](#usage)
- [UI](#ui)
- [API](#api)
- [Prometheus](#prometheus)
- [Grafana](#grafana)
- [Alert Manager](#alert-manager)
- [Contributions](#contributions)
- [License](#license)
- [Goldpinger ![Build Status](https://travis-ci.com/bloomberg/goldpinger)](#goldpinger-build-statushttpstravis-cicombloomberggoldpinger)
- [On the menu](#on-the-menu)
- [Rationale](#rationale)
- [Quick start](#quick-start)
- [Building](#building)
- [Compiling using a multi-stage Dockerfile](#compiling-using-a-multi-stage-dockerfile)
- [Compiling locally](#compiling-locally)
- [Installation](#installation)
- [Authentication with Kubernetes API](#authentication-with-kubernetes-api)
- [Example YAML](#example-yaml)
- [Note on DNS](#note-on-dns)
- [Usage](#usage)
- [UI](#ui)
- [API](#api)
- [Prometheus](#prometheus)
- [Grafana](#grafana)
- [Alert Manager](#alert-manager)
- [Contributions](#contributions)
- [License](#license)
## Rationale
@@ -53,9 +55,6 @@ Getting from [docker hub](https://hub.docker.com/r/bloomberg/goldpinger):
docker pull bloomberg/goldpinger
```
Note, that in order to guarantee correct versions of dependencies, the project [uses `dep`](./Makefile).
## Building
The repo comes with two ways of building a `docker` image: compiling locally, and compiling using a multi-stage `Dockerfile` image. :warning: Depending on your `docker` setup, you might need to prepend the commands below with `sudo`.
@@ -77,27 +76,24 @@ This was contributed via [@michiel](https://github.com/michiel) - kudos !
### Compiling locally
In order to build `Goldpinger`, you are going to need `go` version 1.10+, `dep`, and `docker`.
In order to build `Goldpinger`, you are going to need `go` version 1.13+ and `docker`.
Building from source code consists of compiling the binary and building a [Docker image](./build/Dockerfile-simple):
```sh
# step 0: check out the code into your $GOPATH
go get github.com/bloomberg/goldpinger/cmd/goldpinger
cd $GOPATH/src/github.com/bloomberg/goldpinger
# step 0: check out the code
git clone https://github.com/bloomberg/goldpinger.git
cd goldpinger
# step 1: download the dependencies via dep ensure
make vendor
# step 2: compile the binary for the desired architecture
# step 1: compile the binary for the desired architecture
make bin/goldpinger
# at this stage you should be able to run the binary
./bin/goldpinger --help
# step 3: build the docker image containing the binary
# step 2: build the docker image containing the binary
make build
# step 4: push the image somewhere
# step 3: push the image somewhere
namespace="docker.io/myhandle/" make tag
namespace="docker.io/myhandle/" make push
```
@@ -121,26 +117,38 @@ apiVersion: apps/v1
kind: DaemonSet
metadata:
name: goldpinger
namespace: default
labels:
app: goldpinger
spec:
updateStrategy:
type: RollingUpdate
selector:
matchLabels:
app: goldpinger
version: "1.5.0"
template:
metadata:
annotations:
prometheus.io/scrape: 'true'
prometheus.io/port: '8080'
labels:
app: goldpinger
version: "1.5.0"
spec:
serviceAccount: "goldpinger-serviceaccount"
tolerations:
- key: node-role.kubernetes.io/master
effect: NoSchedule
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 2000
containers:
- name: goldpinger
env:
- name: HOST
value: "0.0.0.0"
- name: PORT
value: "80"
value: "8080"
# injecting real hostname will make for easier to understand graphs/metrics
- name: HOSTNAME
valueFrom:
@@ -151,20 +159,30 @@ spec:
valueFrom:
fieldRef:
fieldPath: status.podIP
image: "docker.io/bloomberg/goldpinger:1.5.0"
image: "docker.io/bloomberg/goldpinger:2.0.2"
imagePullPolicy: Always
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
resources:
limits:
memory: 80Mi
requests:
cpu: 1m
memory: 40Mi
ports:
- containerPort: 80
- containerPort: 8080
name: http
readinessProbe:
httpGet:
path: /healthz
port: 80
port: 8080
initialDelaySeconds: 20
periodSeconds: 5
livenessProbe:
httpGet:
path: /healthz
port: 80
port: 8080
initialDelaySeconds: 20
periodSeconds: 5
---
@@ -172,12 +190,13 @@ apiVersion: v1
kind: Service
metadata:
name: goldpinger
namespace: default
labels:
app: goldpinger
spec:
type: NodePort
ports:
- port: 80
- port: 8080
nodePort: 30080
name: http
selector:
@@ -271,7 +290,7 @@ To get you started, here's a rule that will trigger an alert if there are any no
```yaml
alert: goldpinger_nodes_unhealthy
expr: sum(goldpinger_nodes_health_total{status="unhealthy"})
BY (goldpinger_instance) > 0
BY (instance, goldpinger_instance) > 0
for: 5m
annotations:
description: |

View File

@@ -15,17 +15,18 @@
package main
import (
"log"
"os"
"strconv"
"github.com/go-openapi/loads"
"go.uber.org/zap"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"github.com/bloomberg/goldpinger/pkg/goldpinger"
"github.com/bloomberg/goldpinger/pkg/restapi"
"github.com/bloomberg/goldpinger/pkg/restapi/operations"
"github.com/bloomberg/goldpinger/v3/pkg/goldpinger"
"github.com/bloomberg/goldpinger/v3/pkg/restapi"
"github.com/bloomberg/goldpinger/v3/pkg/restapi/operations"
flags "github.com/jessevdk/go-flags"
)
@@ -34,14 +35,37 @@ var (
Version, Build string
)
func main() {
func getLogger() *zap.Logger {
var logger *zap.Logger
var err error
log.Println("Goldpinger version:", Version, "build:", Build)
// 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()
}
if err != nil {
panic(err)
}
zap.ReplaceGlobals(logger)
return logger
}
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 {
log.Fatalln(err)
logger.Error("Coud not parse swagger", zap.Error(err))
}
// create new service API
@@ -58,7 +82,7 @@ func main() {
for _, optsGroup := range api.CommandLineOptionsGroups {
_, err := parser.AddGroup(optsGroup.ShortDescription, optsGroup.LongDescription, optsGroup.Options)
if err != nil {
log.Fatalln(err)
logger.Error("Coud not add flag group", zap.Error(err))
}
}
@@ -75,19 +99,19 @@ func main() {
// make a kubernetes client
var config *rest.Config
if goldpinger.GoldpingerConfig.KubeConfigPath == "" {
log.Println("Kubeconfig not specified, trying to use in cluster config")
logger.Info("Kubeconfig not specified, trying to use in cluster config")
config, err = rest.InClusterConfig()
} else {
log.Println("Kubeconfig specified in ", goldpinger.GoldpingerConfig.KubeConfigPath)
logger.Info("Kubeconfig specified", zap.String("path", goldpinger.GoldpingerConfig.KubeConfigPath))
config, err = clientcmd.BuildConfigFromFlags("", goldpinger.GoldpingerConfig.KubeConfigPath)
}
if err != nil {
log.Fatalln("Error getting config ", err.Error())
logger.Fatal("Error getting config ", zap.Error(err))
}
// create the clientset
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
log.Fatalln("kubernetes.NewForConfig error ", err.Error())
logger.Fatal("kubernetes.NewForConfig error ", zap.Error(err))
}
goldpinger.GoldpingerConfig.KubernetesClient = clientset
@@ -97,20 +121,19 @@ func main() {
}
if goldpinger.GoldpingerConfig.PodIP == "" {
log.Println("PodIP not set: pinging all pods")
logger.Info("PodIP not set: pinging all pods")
}
if goldpinger.GoldpingerConfig.PingNumber == 0 {
log.Println("--ping-number set to 0: pinging all pods")
logger.Info("--ping-number set to 0: pinging all pods")
}
goldpinger.GoldpingerConfig.PodSelecter = goldpinger.NewPodSelecter(goldpinger.GoldpingerConfig.PingNumber, goldpinger.GoldpingerConfig.PodIP, goldpinger.GetAllPods)
server.ConfigureAPI()
goldpinger.StartUpdater()
log.Println("All good, starting serving the API")
logger.Info("All good, starting serving the API")
// serve API
if err := server.Serve(); err != nil {
log.Fatalln(err)
logger.Fatal("Error serving the API", zap.Error(err))
}
}

View File

@@ -25,13 +25,17 @@ spec:
app: goldpinger
spec:
serviceAccount: "goldpinger-serviceaccount"
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 2000
containers:
- name: goldpinger
env:
- name: HOST
value: "0.0.0.0"
- name: PORT
value: "80"
value: "8080"
# injecting real hostname will make for easier to understand graphs/metrics
- name: HOSTNAME
valueFrom:
@@ -42,10 +46,32 @@ spec:
valueFrom:
fieldRef:
fieldPath: status.podIP
image: "docker.io/bloomberg/goldpinger:1.4.0"
image: "docker.io/bloomberg/goldpinger:2.0.0"
imagePullPolicy: Always
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
resources:
limits:
memory: 80Mi
requests:
cpu: 1m
memory: 40Mi
ports:
- containerPort: 80
- containerPort: 8080
name: http
readinessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 20
periodSeconds: 5
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 20
periodSeconds: 5
---
apiVersion: v1
kind: Service
@@ -57,7 +83,7 @@ metadata:
spec:
type: NodePort
ports:
- port: 80
- port: 8080
nodePort: 30080
name: http
selector:

View File

@@ -5,20 +5,24 @@ metadata:
name: goldpinger
labels:
app: goldpinger
version: "1.5.0"
version: "2.0.0"
spec:
updateStrategy:
type: RollingUpdate
selector:
matchLabels:
app: goldpinger
version: "1.5.0"
version: "2.0.0"
template:
metadata:
labels:
app: goldpinger
version: "1.5.0"
version: "2.0.0"
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 2000
# if you'd like to use a secret to inject a kubeconfig, you can do it like this
volumes:
- name: kubeconfig
@@ -30,7 +34,7 @@ spec:
- name: HOST
value: "0.0.0.0"
- name: PORT
value: "80"
value: "8080"
# kubeconfig needs to match the location of what's injected in the secret
# if not specified goldpinger will default to using in-cluster config
- name: KUBECONFIG
@@ -48,20 +52,30 @@ spec:
valueFrom:
fieldRef:
fieldPath: status.podIP
image: "docker.io/bloomberg/goldpinger:1.5.0"
image: "docker.io/bloomberg/goldpinger:2.0.0"
imagePullPolicy: Always
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
resources:
limits:
memory: 80Mi
requests:
cpu: 1m
memory: 40Mi
ports:
- containerPort: 80
- containerPort: 8080
name: http
readinessProbe:
httpGet:
path: /healthz
port: 80
port: 8080
initialDelaySeconds: 20
periodSeconds: 5
livenessProbe:
httpGet:
path: /healthz
port: 80
port: 8080
initialDelaySeconds: 20
periodSeconds: 5
volumeMounts:
@@ -78,7 +92,7 @@ metadata:
spec:
type: NodePort
ports:
- port: 80
- port: 8080
nodePort: 30080
name: http
selector:

View File

@@ -33,7 +33,7 @@
"rgba(237, 129, 40, 0.89)",
"rgba(245, 54, 54, 0.9)"
],
"datasource": "K8S",
"datasource": "$datasource",
"editable": true,
"error": false,
"format": "none",
@@ -113,7 +113,7 @@
"rgba(237, 129, 40, 0.89)",
"rgba(245, 54, 54, 0.9)"
],
"datasource": "K8S",
"datasource": "$datasource",
"editable": true,
"error": false,
"format": "none",
@@ -199,7 +199,7 @@
"value": "avg"
}
],
"datasource": "K8S",
"datasource": "$datasource",
"editable": true,
"error": false,
"fontSize": "100%",
@@ -256,7 +256,7 @@
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "K8S",
"datasource": "$datasource",
"editable": true,
"error": false,
"fill": 1,
@@ -340,7 +340,7 @@
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "K8S",
"datasource": "$datasource",
"editable": true,
"error": false,
"fill": 1,
@@ -436,7 +436,7 @@
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "K8S",
"datasource": "$datasource",
"editable": true,
"error": false,
"fill": 1,
@@ -519,7 +519,7 @@
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "K8S",
"datasource": "$datasource",
"editable": true,
"error": false,
"fill": 1,
@@ -602,7 +602,7 @@
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "K8S",
"datasource": "$datasource",
"editable": true,
"error": false,
"fill": 1,
@@ -697,7 +697,7 @@
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "K8S",
"datasource": "$datasource",
"editable": true,
"error": false,
"fill": 1,
@@ -781,7 +781,7 @@
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "K8S",
"datasource": "$datasource",
"editable": true,
"error": false,
"fill": 1,
@@ -865,7 +865,7 @@
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "K8S",
"datasource": "$datasource",
"editable": true,
"error": false,
"fill": 1,
@@ -958,10 +958,25 @@
"tags": [],
"templating": {
"list": [
{
"current": {
"text": "prometheus",
"value": "prometheus"
},
"hide": 0,
"label": "datasource",
"name": "datasource",
"options": [],
"query": "prometheus",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"type": "datasource"
},
{
"allValue": ".*",
"current": {},
"datasource": "K8S",
"datasource": "$datasource",
"hide": 0,
"includeAll": true,
"label": "Instance",
@@ -981,7 +996,7 @@
{
"allValue": ".*",
"current": {},
"datasource": "K8S",
"datasource": "$datasource",
"hide": 0,
"includeAll": true,
"label": "Call Type",

50
go.mod Normal file
View File

@@ -0,0 +1,50 @@
module github.com/bloomberg/goldpinger/v3
go 1.14
require (
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 // indirect
github.com/cespare/xxhash v1.1.0
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680 // indirect
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 // indirect
github.com/go-openapi/analysis v0.17.2 // indirect
github.com/go-openapi/errors v0.17.2
github.com/go-openapi/jsonpointer v0.17.2 // indirect
github.com/go-openapi/jsonreference v0.17.2 // indirect
github.com/go-openapi/loads v0.17.2
github.com/go-openapi/runtime v0.17.2
github.com/go-openapi/spec v0.17.2
github.com/go-openapi/strfmt v0.17.2
github.com/go-openapi/swag v0.17.2
github.com/go-openapi/validate v0.17.2
github.com/gogo/protobuf v0.0.0-20170330071051-c0656edd0d9e // indirect
github.com/golang/glog v0.0.0-20141105023935-44145f04b68c // indirect
github.com/google/btree v1.0.0 // indirect
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367 // indirect
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d // indirect
github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7 // indirect
github.com/imdario/mergo v0.3.5 // indirect
github.com/jessevdk/go-flags v1.4.0
github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/prometheus/client_golang v0.9.1
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 // indirect
github.com/prometheus/common v0.0.0-20181020173914-7e9e6cabbd39 // indirect
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d // indirect
github.com/spf13/pflag v1.0.1 // indirect
github.com/stuartnelson3/go-rendezvous v0.2.0
go.uber.org/zap v1.14.1
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 // indirect
golang.org/x/image v0.0.0-20190220214146-31aff87c08e9
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a // indirect
golang.org/x/time v0.0.0-20161028155119-f51c12702a4d // indirect
gopkg.in/inf.v0 v0.9.0 // indirect
k8s.io/api v0.0.0-20181004124137-fd83cbc87e76 // indirect
k8s.io/apimachinery v0.0.0-20180913025736-6dd46049f395
k8s.io/client-go v9.0.0+incompatible
)

189
go.sum Normal file
View File

@@ -0,0 +1,189 @@
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/PuerkitoBio/purell v1.1.0 h1:rmGxhojJlM0tuKtfdvliR84CFHljx9ag64t2xmVkjK4=
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf h1:eg0MeVzsP1G42dRafH3vf+al2vQIJU0YHX+1Tw87oco=
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docker/go-units v0.3.3 h1:Xk8S3Xj5sLGlG5g67hJmYMmUgXv5N4PhkjJHHqrwnTk=
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680 h1:ZktWZesgun21uEDrwW7iEV1zPCGQldM2atlJZ3TdvVM=
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 h1:DujepqpGd1hyOd7aW59XpK7Qymp8iy83xq74fLr21is=
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI=
github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
github.com/go-openapi/analysis v0.17.2 h1:eYp14J1o8TTSCzndHBtsNuckikV1PfZOSnx4BcBeu0c=
github.com/go-openapi/analysis v0.17.2/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
github.com/go-openapi/errors v0.17.2 h1:azEQ8Fnx0jmtFF2fxsnmd6I0x6rsweUF63qqSO1NmKk=
github.com/go-openapi/errors v0.17.2/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
github.com/go-openapi/jsonpointer v0.17.2 h1:3ekBy41gar/iJi2KSh/au/PrC2vpLr85upF/UZmm3W0=
github.com/go-openapi/jsonpointer v0.17.2/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/jsonreference v0.17.2 h1:lF3z7AH8dd0IKXc1zEBi1dj0B4XgVb5cVjn39dCK3Ls=
github.com/go-openapi/jsonreference v0.17.2/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
github.com/go-openapi/loads v0.17.2 h1:tEXYu6Xc0pevpzzQx5ghrMN9F7IVpN/+u4iD3rkYE5o=
github.com/go-openapi/loads v0.17.2/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA=
github.com/go-openapi/runtime v0.17.2 h1:/ZK67ikFhQAMFFH/aPu2MaGH7QjP4wHBvHYOVIzDAw0=
github.com/go-openapi/runtime v0.17.2/go.mod h1:QO936ZXeisByFmZEO1IS1Dqhtf4QV1sYYFtIq6Ld86Q=
github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/spec v0.17.2 h1:eb2NbuCnoe8cWAxhtK6CfMWUYmiFEZJ9Hx3Z2WRwJ5M=
github.com/go-openapi/spec v0.17.2/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
github.com/go-openapi/strfmt v0.17.2 h1:2KDns36DMHXG9/iYkOjiX+/8fKK9GCU5ELZ+J6qcRVA=
github.com/go-openapi/strfmt v0.17.2/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
github.com/go-openapi/swag v0.17.2 h1:K/ycE/XTUDFltNHSO32cGRUhrVGJD64o8WgAIZNyc3k=
github.com/go-openapi/swag v0.17.2/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
github.com/go-openapi/validate v0.17.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
github.com/go-openapi/validate v0.17.2 h1:lwFfiS4sv5DvOrsYDsYq4N7UU8ghXiYtPJ+VcQnC3Xg=
github.com/go-openapi/validate v0.17.2/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
github.com/gogo/protobuf v0.0.0-20170330071051-c0656edd0d9e h1:ago6fNuQ6IhszPsXkeU7qRCyfsIX7L67WDybsAPkLl8=
github.com/gogo/protobuf v0.0.0-20170330071051-c0656edd0d9e/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/glog v0.0.0-20141105023935-44145f04b68c h1:CbdkBQ1/PiAo0FYJhQGwASD8wrgNvTdf01g6+O9tNuA=
github.com/golang/glog v0.0.0-20141105023935-44145f04b68c/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367 h1:ScAXWS+TR6MZKex+7Z8rneuSJH+FSDqd6ocQyl+ZHo4=
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.0.0 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d h1:7XGaL1e6bYS1yIonGp9761ExpPPV1ui0SAC59Yube9k=
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7 h1:6TSoaYExHper8PYsJu23GWVNOyYRCSnIFyxKgLSZ54w=
github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/imdario/mergo v0.3.5 h1:JboBksRwiiAJWvIYJVo46AfV+IAIKZpfrSzVKj42R4Q=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3 h1:/UewZcckqhvnnS0C6r3Sher2hSEbVmM6Ogpcjen08+Y=
github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329 h1:2gxZ0XQIU/5z3Z3bUBu+FXuk2pFbkN6tcwi/pjyaDic=
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.1 h1:K47Rk0v/fkEfwfQet2KWhscE0cJzjgCCDBG2KHZoVno=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/common v0.0.0-20181020173914-7e9e6cabbd39 h1:Cto4X6SVMWRPBkJ/3YHn1iDGDGc/Z+sW+AEMKHMVvN4=
github.com/prometheus/common v0.0.0-20181020173914-7e9e6cabbd39/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d h1:GoAlyOgbOEIFdaDqxJVlbOQ1DtGmZWs/Qau0hIlk+WQ=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/pflag v1.0.1 h1:aCvUg6QPl3ibpQUxyLkrEkCHtPqYJL4x9AuhqVqFis4=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stuartnelson3/go-rendezvous v0.2.0 h1:H5IexrsptBzCMQEjTRrNH20MVXGqpFf1JUCPglaxd6I=
github.com/stuartnelson3/go-rendezvous v0.2.0/go.mod h1:njfgP6zISyRnZ3iQN13NSEILfSNLN4ysxBoGxHs5PJ0=
go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.14.1 h1:nYDKopTbvAPq/NrUVZwT15y2lpROBiLLyoRTbXOYWOo=
go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/image v0.0.0-20190220214146-31aff87c08e9 h1:+vH8qNweCrORN49012OX3h0oWEXO3p+rRnpAGQinddk=
golang.org/x/image v0.0.0-20190220214146-31aff87c08e9/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a h1:WXEvlFVvvGxCJLG6REjsT03iWnKLEWinaScsxF2Vm2o=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/time v0.0.0-20161028155119-f51c12702a4d h1:TnM+PKb3ylGmZvyPXmo9m/wktg7Jn/a/fNmr33HSj8g=
golang.org/x/time v0.0.0-20161028155119-f51c12702a4d/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/inf.v0 v0.9.0 h1:3zYtXIO92bvsdS3ggAdA8Gb4Azj0YU+TVY1uGYNFA8o=
gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
k8s.io/api v0.0.0-20181004124137-fd83cbc87e76 h1:cGc6jt7tNK7a2WfgNKjxjoU/UXXr9Q7JTqvCupZ+6+Y=
k8s.io/api v0.0.0-20181004124137-fd83cbc87e76/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA=
k8s.io/apimachinery v0.0.0-20180913025736-6dd46049f395 h1:X+c9tYTDc9Pmt+Z1YSMqmUTCYf13VYe1u+ZwzjgpK0M=
k8s.io/apimachinery v0.0.0-20180913025736-6dd46049f395/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0=
k8s.io/client-go v9.0.0+incompatible h1:2kqW3X2xQ9SbFvWZjGEHBLlWc1LG9JIJNXWkuqwdZ3A=
k8s.io/client-go v9.0.0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s=

View File

@@ -6,12 +6,10 @@ package client
// Editing this file might prove futile when you re-run the swagger generate command
import (
"github.com/bloomberg/goldpinger/v3/pkg/client/operations"
"github.com/go-openapi/runtime"
httptransport "github.com/go-openapi/runtime/client"
strfmt "github.com/go-openapi/strfmt"
"github.com/bloomberg/goldpinger/pkg/client/operations"
"github.com/go-openapi/strfmt"
)
// Default goldpinger HTTP client.
@@ -56,9 +54,7 @@ func New(transport runtime.ClientTransport, formats strfmt.Registry) *Goldpinger
cli := new(Goldpinger)
cli.Transport = transport
cli.Operations = operations.New(transport, formats)
return cli
}
@@ -103,7 +99,7 @@ func (cfg *TransportConfig) WithSchemes(schemes []string) *TransportConfig {
// Goldpinger is a client for goldpinger
type Goldpinger struct {
Operations *operations.Client
Operations operations.ClientService
Transport runtime.ClientTransport
}
@@ -111,7 +107,5 @@ type Goldpinger struct {
// SetTransport changes the transport on the client and all its subresources
func (c *Goldpinger) SetTransport(transport runtime.ClientTransport) {
c.Transport = transport
c.Operations.SetTransport(transport)
}

View File

@@ -13,8 +13,7 @@ import (
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
strfmt "github.com/go-openapi/strfmt"
"github.com/go-openapi/strfmt"
)
// NewCheckAllPodsParams creates a new CheckAllPodsParams object

View File

@@ -10,10 +10,9 @@ import (
"io"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
strfmt "github.com/go-openapi/strfmt"
models "github.com/bloomberg/goldpinger/pkg/models"
"github.com/bloomberg/goldpinger/v3/pkg/models"
)
// CheckAllPodsReader is a Reader for the CheckAllPods structure.
@@ -24,7 +23,6 @@ type CheckAllPodsReader struct {
// ReadResponse reads a server response into the received o.
func (o *CheckAllPodsReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 200:
result := NewCheckAllPodsOK()
if err := result.readResponse(response, consumer, o.formats); err != nil {
@@ -54,6 +52,10 @@ func (o *CheckAllPodsOK) Error() string {
return fmt.Sprintf("[GET /check_all][%d] checkAllPodsOK %+v", 200, o.Payload)
}
func (o *CheckAllPodsOK) GetPayload() *models.CheckAllResults {
return o.Payload
}
func (o *CheckAllPodsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
o.Payload = new(models.CheckAllResults)

View File

@@ -13,8 +13,7 @@ import (
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
strfmt "github.com/go-openapi/strfmt"
"github.com/go-openapi/strfmt"
)
// NewCheckServicePodsParams creates a new CheckServicePodsParams object

View File

@@ -10,10 +10,9 @@ import (
"io"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
strfmt "github.com/go-openapi/strfmt"
models "github.com/bloomberg/goldpinger/pkg/models"
"github.com/bloomberg/goldpinger/v3/pkg/models"
)
// CheckServicePodsReader is a Reader for the CheckServicePods structure.
@@ -24,7 +23,6 @@ type CheckServicePodsReader struct {
// ReadResponse reads a server response into the received o.
func (o *CheckServicePodsReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 200:
result := NewCheckServicePodsOK()
if err := result.readResponse(response, consumer, o.formats); err != nil {
@@ -54,6 +52,10 @@ func (o *CheckServicePodsOK) Error() string {
return fmt.Sprintf("[GET /check][%d] checkServicePodsOK %+v", 200, o.Payload)
}
func (o *CheckServicePodsOK) GetPayload() *models.CheckResults {
return o.Payload
}
func (o *CheckServicePodsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
o.Payload = new(models.CheckResults)

View File

@@ -13,8 +13,7 @@ import (
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
strfmt "github.com/go-openapi/strfmt"
"github.com/go-openapi/strfmt"
)
// NewHealthzParams creates a new HealthzParams object

View File

@@ -10,10 +10,9 @@ import (
"io"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
strfmt "github.com/go-openapi/strfmt"
models "github.com/bloomberg/goldpinger/pkg/models"
"github.com/bloomberg/goldpinger/v3/pkg/models"
)
// HealthzReader is a Reader for the Healthz structure.
@@ -24,14 +23,12 @@ type HealthzReader struct {
// ReadResponse reads a server response into the received o.
func (o *HealthzReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 200:
result := NewHealthzOK()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return result, nil
case 503:
result := NewHealthzServiceUnavailable()
if err := result.readResponse(response, consumer, o.formats); err != nil {
@@ -61,6 +58,10 @@ func (o *HealthzOK) Error() string {
return fmt.Sprintf("[GET /healthz][%d] healthzOK %+v", 200, o.Payload)
}
func (o *HealthzOK) GetPayload() *models.HealthCheckResults {
return o.Payload
}
func (o *HealthzOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
o.Payload = new(models.HealthCheckResults)
@@ -90,6 +91,10 @@ func (o *HealthzServiceUnavailable) Error() string {
return fmt.Sprintf("[GET /healthz][%d] healthzServiceUnavailable %+v", 503, o.Payload)
}
func (o *HealthzServiceUnavailable) GetPayload() *models.HealthCheckResults {
return o.Payload
}
func (o *HealthzServiceUnavailable) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
o.Payload = new(models.HealthCheckResults)

View File

@@ -6,13 +6,14 @@ package operations
// Editing this file might prove futile when you re-run the swagger generate command
import (
"github.com/go-openapi/runtime"
"fmt"
strfmt "github.com/go-openapi/strfmt"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
)
// New creates a new operations API client.
func New(transport runtime.ClientTransport, formats strfmt.Registry) *Client {
func New(transport runtime.ClientTransport, formats strfmt.Registry) ClientService {
return &Client{transport: transport, formats: formats}
}
@@ -24,8 +25,21 @@ type Client struct {
formats strfmt.Registry
}
// ClientService is the interface for Client methods
type ClientService interface {
CheckAllPods(params *CheckAllPodsParams) (*CheckAllPodsOK, error)
CheckServicePods(params *CheckServicePodsParams) (*CheckServicePodsOK, error)
Healthz(params *HealthzParams) (*HealthzOK, error)
Ping(params *PingParams) (*PingOK, error)
SetTransport(transport runtime.ClientTransport)
}
/*
CheckAllPods Queries the API server for all other pods in this service, and makes all of them query all of their neighbours, using their pods IPs. Calls their /check endpoint.
CheckAllPods Queries the API server for all other pods in this service, and makes all of them query all of their neighbours, using their pods IPs. Calls their /check endpoint.
*/
func (a *Client) CheckAllPods(params *CheckAllPodsParams) (*CheckAllPodsOK, error) {
// TODO: Validate the params before sending
@@ -38,7 +52,7 @@ func (a *Client) CheckAllPods(params *CheckAllPodsParams) (*CheckAllPodsOK, erro
Method: "GET",
PathPattern: "/check_all",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{""},
ConsumesMediaTypes: []string{"application/json"},
Schemes: []string{"http"},
Params: params,
Reader: &CheckAllPodsReader{formats: a.formats},
@@ -48,12 +62,18 @@ func (a *Client) CheckAllPods(params *CheckAllPodsParams) (*CheckAllPodsOK, erro
if err != nil {
return nil, err
}
return result.(*CheckAllPodsOK), nil
success, ok := result.(*CheckAllPodsOK)
if ok {
return success, nil
}
// unexpected success response
// safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue
msg := fmt.Sprintf("unexpected success response for checkAllPods: API contract not enforced by server. Client expected to get an error, but got: %T", result)
panic(msg)
}
/*
CheckServicePods Queries the API server for all other pods in this service, and pings them via their pods IPs. Calls their /ping endpoint
CheckServicePods Queries the API server for all other pods in this service, and pings them via their pods IPs. Calls their /ping endpoint
*/
func (a *Client) CheckServicePods(params *CheckServicePodsParams) (*CheckServicePodsOK, error) {
// TODO: Validate the params before sending
@@ -66,7 +86,7 @@ func (a *Client) CheckServicePods(params *CheckServicePodsParams) (*CheckService
Method: "GET",
PathPattern: "/check",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{""},
ConsumesMediaTypes: []string{"application/json"},
Schemes: []string{"http"},
Params: params,
Reader: &CheckServicePodsReader{formats: a.formats},
@@ -76,12 +96,18 @@ func (a *Client) CheckServicePods(params *CheckServicePodsParams) (*CheckService
if err != nil {
return nil, err
}
return result.(*CheckServicePodsOK), nil
success, ok := result.(*CheckServicePodsOK)
if ok {
return success, nil
}
// unexpected success response
// safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue
msg := fmt.Sprintf("unexpected success response for checkServicePods: API contract not enforced by server. Client expected to get an error, but got: %T", result)
panic(msg)
}
/*
Healthz The healthcheck endpoint provides detailed information about the health of a web service. If each of the components required by the service are healthy, then the service is considered healthy and will return a 200 OK response. If any of the components needed by the service are unhealthy, then a 503 Service Unavailable response will be provided.
Healthz The healthcheck endpoint provides detailed information about the health of a web service. If each of the components required by the service are healthy, then the service is considered healthy and will return a 200 OK response. If any of the components needed by the service are unhealthy, then a 503 Service Unavailable response will be provided.
*/
func (a *Client) Healthz(params *HealthzParams) (*HealthzOK, error) {
// TODO: Validate the params before sending
@@ -94,7 +120,7 @@ func (a *Client) Healthz(params *HealthzParams) (*HealthzOK, error) {
Method: "GET",
PathPattern: "/healthz",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{""},
ConsumesMediaTypes: []string{"application/json"},
Schemes: []string{"http"},
Params: params,
Reader: &HealthzReader{formats: a.formats},
@@ -104,12 +130,18 @@ func (a *Client) Healthz(params *HealthzParams) (*HealthzOK, error) {
if err != nil {
return nil, err
}
return result.(*HealthzOK), nil
success, ok := result.(*HealthzOK)
if ok {
return success, nil
}
// unexpected success response
// safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue
msg := fmt.Sprintf("unexpected success response for healthz: API contract not enforced by server. Client expected to get an error, but got: %T", result)
panic(msg)
}
/*
Ping return query stats
Ping return query stats
*/
func (a *Client) Ping(params *PingParams) (*PingOK, error) {
// TODO: Validate the params before sending
@@ -122,7 +154,7 @@ func (a *Client) Ping(params *PingParams) (*PingOK, error) {
Method: "GET",
PathPattern: "/ping",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{""},
ConsumesMediaTypes: []string{"application/json"},
Schemes: []string{"http"},
Params: params,
Reader: &PingReader{formats: a.formats},
@@ -132,8 +164,14 @@ func (a *Client) Ping(params *PingParams) (*PingOK, error) {
if err != nil {
return nil, err
}
return result.(*PingOK), nil
success, ok := result.(*PingOK)
if ok {
return success, nil
}
// unexpected success response
// safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue
msg := fmt.Sprintf("unexpected success response for ping: API contract not enforced by server. Client expected to get an error, but got: %T", result)
panic(msg)
}
// SetTransport changes the transport on the client

View File

@@ -13,8 +13,7 @@ import (
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
strfmt "github.com/go-openapi/strfmt"
"github.com/go-openapi/strfmt"
)
// NewPingParams creates a new PingParams object

View File

@@ -10,10 +10,9 @@ import (
"io"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
strfmt "github.com/go-openapi/strfmt"
models "github.com/bloomberg/goldpinger/pkg/models"
"github.com/bloomberg/goldpinger/v3/pkg/models"
)
// PingReader is a Reader for the Ping structure.
@@ -24,7 +23,6 @@ type PingReader struct {
// ReadResponse reads a server response into the received o.
func (o *PingReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 200:
result := NewPingOK()
if err := result.readResponse(response, consumer, o.formats); err != nil {
@@ -54,6 +52,10 @@ func (o *PingOK) Error() string {
return fmt.Sprintf("[GET /ping][%d] pingOK %+v", 200, o.Payload)
}
func (o *PingOK) GetPayload() *models.PingResults {
return o.Payload
}
func (o *PingOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
o.Payload = new(models.PingResults)

View File

@@ -15,33 +15,49 @@
package goldpinger
import (
"context"
"errors"
"fmt"
"net"
"sync"
"time"
apiclient "github.com/bloomberg/goldpinger/pkg/client"
"github.com/bloomberg/goldpinger/pkg/models"
apiclient "github.com/bloomberg/goldpinger/v3/pkg/client"
"github.com/bloomberg/goldpinger/v3/pkg/client/operations"
"github.com/bloomberg/goldpinger/v3/pkg/models"
httptransport "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
"go.uber.org/zap"
)
// CheckNeighbours queries the kubernetes API server for all other goldpinger pods
// then calls Ping() on each one
func CheckNeighbours(ps *PodSelecter) *models.CheckResults {
return PingAllPods(ps.SelectPods())
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()
}
return &final
}
// CheckNeighboursNeighbours queries the kubernetes API server for all other goldpinger
// pods then calls Check() on each one
func CheckNeighboursNeighbours(ps *PodSelecter) *models.CheckAllResults {
return CheckAllPods(ps.SelectPods())
func CheckNeighboursNeighbours(ctx context.Context) *models.CheckAllResults {
return CheckAllPods(ctx, SelectPods())
}
type PingAllPodsResult struct {
podName string
podResult models.PodResult
hostIPv4 strfmt.IPv4
podIP string
deleted bool
}
func pickPodHostIP(podIP, hostIP string) string {
@@ -53,8 +69,8 @@ func pickPodHostIP(podIP, hostIP string) string {
func checkDNS() *models.DNSResults {
results := models.DNSResults{}
for _, host := range GoldpingerConfig.DnsHosts{
for _, host := range GoldpingerConfig.DnsHosts {
var dnsResult models.DNSResult
start := time.Now()
@@ -69,70 +85,14 @@ func checkDNS() *models.DNSResults {
return &results
}
func PingAllPods(pods map[string]string) *models.CheckResults {
result := models.CheckResults{}
ch := make(chan PingAllPodsResult, len(pods))
wg := sync.WaitGroup{}
wg.Add(len(pods))
for podIP, hostIP := range pods {
go func(podIP string, hostIP string) {
var channelResult PingAllPodsResult
CountCall("made", "ping")
timer := GetLabeledPeersCallsTimer("ping", hostIP, podIP)
start := time.Now()
resp, err := getClient(pickPodHostIP(podIP, hostIP)).Operations.Ping(nil)
channelResult.hostIPv4.UnmarshalText([]byte(hostIP))
var OK = (err == nil)
if OK {
responseTime := time.Since(start).Nanoseconds() / int64(time.Millisecond)
channelResult.podResult = models.PodResult{HostIP: channelResult.hostIPv4, OK: &OK, Response: resp.Payload, StatusCode: 200, ResponseTimeMs: responseTime}
timer.ObserveDuration()
} else {
channelResult.podResult = models.PodResult{HostIP: channelResult.hostIPv4, OK: &OK, Error: err.Error(), StatusCode: 500}
CountError("ping")
}
channelResult.podIP = podIP
ch <- channelResult
wg.Done()
}(podIP, hostIP)
}
if len(GoldpingerConfig.DnsHosts) > 0 {
result.DNSResults = *checkDNS()
}
wg.Wait()
close(ch)
counterHealthy, counterUnhealthy := 0.0, 0.0
result.PodResults = make(map[string]models.PodResult)
for response := range ch {
var podIPv4 strfmt.IPv4
podIPv4.UnmarshalText([]byte(response.podIP))
if *response.podResult.OK {
counterHealthy++
} else {
counterUnhealthy++
}
result.PodResults[response.podIP] = response.podResult
}
CountHealthyUnhealthyNodes(counterHealthy, counterUnhealthy)
return &result
}
type CheckServicePodsResult struct {
podName string
checkAllPodResult models.CheckAllPodResult
hostIPv4 strfmt.IPv4
podIP string
podIPv4 strfmt.IPv4
}
func CheckAllPods(pods map[string]string) *models.CheckAllResults {
func CheckAllPods(checkAllCtx context.Context, pods map[string]*GoldpingerPod) *models.CheckAllResults {
result := models.CheckAllResults{Responses: make(map[string]models.CheckAllPodResult)}
@@ -140,52 +100,86 @@ func CheckAllPods(pods map[string]string) *models.CheckAllResults {
wg := sync.WaitGroup{}
wg.Add(len(pods))
for podIP, hostIP := range pods {
for _, pod := range pods {
go func(podIP string, hostIP string) {
var channelResult CheckServicePodsResult
go func(pod *GoldpingerPod) {
// logger
logger := zap.L().With(
zap.String("op", "check"),
zap.String("name", pod.Name),
zap.String("hostIP", pod.HostIP),
zap.String("podIP", pod.PodIP),
)
// stats
CountCall("made", "check")
timer := GetLabeledPeersCallsTimer("check", hostIP, podIP)
resp, err := getClient(pickPodHostIP(podIP, hostIP)).Operations.CheckServicePods(nil)
timer := GetLabeledPeersCallsTimer("check", pod.HostIP, pod.PodIP)
channelResult.hostIPv4.UnmarshalText([]byte(hostIP))
var OK = (err == nil)
if OK {
channelResult.checkAllPodResult = models.CheckAllPodResult{
OK: &OK,
HostIP: channelResult.hostIPv4,
Response: resp.Payload,
}
timer.ObserveDuration()
} else {
// setup
var channelResult CheckServicePodsResult
channelResult.podName = pod.Name
channelResult.hostIPv4.UnmarshalText([]byte(pod.HostIP))
channelResult.podIPv4.UnmarshalText([]byte(pod.PodIP))
client, err := getClient(pickPodHostIP(pod.PodIP, pod.HostIP))
OK := false
if err != nil {
logger.Warn("Couldn't get a client for Check", zap.Error(err))
channelResult.checkAllPodResult = models.CheckAllPodResult{
OK: &OK,
PodIP: channelResult.podIPv4,
HostIP: channelResult.hostIPv4,
Error: err.Error(),
}
CountError("checkAll")
} else {
checkCtx, cancel := context.WithTimeout(
checkAllCtx,
time.Duration(GoldpingerConfig.CheckTimeoutMs)*time.Millisecond,
)
defer cancel()
params := operations.NewCheckServicePodsParamsWithContext(checkCtx)
resp, err := client.Operations.CheckServicePods(params)
OK = (err == nil)
if OK {
logger.Debug("Check Ok")
channelResult.checkAllPodResult = models.CheckAllPodResult{
OK: &OK,
PodIP: channelResult.podIPv4,
HostIP: channelResult.hostIPv4,
Response: resp.Payload,
}
timer.ObserveDuration()
} else {
logger.Warn("Check returned error", zap.Error(err))
channelResult.checkAllPodResult = models.CheckAllPodResult{
OK: &OK,
PodIP: channelResult.podIPv4,
HostIP: channelResult.hostIPv4,
Error: err.Error(),
}
CountError("checkAll")
}
}
channelResult.podIP = podIP
ch <- channelResult
wg.Done()
}(podIP, hostIP)
}(pod)
}
wg.Wait()
close(ch)
for response := range ch {
var podIPv4 strfmt.IPv4
podIPv4.UnmarshalText([]byte(response.podIP))
result.Responses[response.podIP] = response.checkAllPodResult
result.Responses[response.podName] = response.checkAllPodResult
result.Hosts = append(result.Hosts, &models.CheckAllResultsHostsItems0{
HostIP: response.hostIPv4,
PodIP: podIPv4,
PodName: response.podName,
HostIP: response.hostIPv4,
PodIP: response.podIPv4,
})
if response.checkAllPodResult.Response != nil &&
response.checkAllPodResult.Response.DNSResults != nil {
response.checkAllPodResult.Response.DNSResults != nil {
if result.DNSResults == nil {
result.DNSResults = make(map[string]models.DNSResults)
}
@@ -193,7 +187,7 @@ func CheckAllPods(pods map[string]string) *models.CheckAllResults {
if result.DNSResults[host] == nil {
result.DNSResults[host] = make(map[string]models.DNSResult)
}
result.DNSResults[host][response.podIP] = response.checkAllPodResult.Response.DNSResults[host]
result.DNSResults[host][response.podName] = response.checkAllPodResult.Response.DNSResults[host]
}
}
}
@@ -211,11 +205,14 @@ func HealthCheck() *models.HealthCheckResults {
return &result
}
func getClient(hostIP string) *apiclient.Goldpinger {
func getClient(hostIP string) (*apiclient.Goldpinger, error) {
if hostIP == "" {
return nil, errors.New("Host or pod IP empty, can't make a call")
}
host := fmt.Sprintf("%s:%d", hostIP, GoldpingerConfig.Port)
transport := httptransport.New(host, "", nil)
client := apiclient.New(transport, strfmt.Default)
apiclient.Default.SetTransport(transport)
return client
return client, nil
}

View File

@@ -23,14 +23,20 @@ var GoldpingerConfig = struct {
StaticFilePath string `long:"static-file-path" description:"Folder for serving static files" env:"STATIC_FILE_PATH"`
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"`
Hostname string `long:"hostname" description:"Hostname to use" env:"HOSTNAME"`
PodIP string `long:"pod-ip" description:"Pod IP to use" env:"POD_IP"`
PodName string `long:"pod-name" description:"The name of this pod - used to select --ping-number of pods using rendezvous hashing" env:"POD_NAME"`
PingNumber uint `long:"ping-number" description:"Number of peers to ping. A value of 0 indicates all peers should be pinged." default:"0" env:"PING_NUMBER"`
Port int `long:"client-port-override" description:"(for testing) use this port when calling other instances" env:"CLIENT_PORT_OVERRIDE"`
UseHostIP bool `long:"use-host-ip" description:"When making the calls, use host ip (defaults to pod ip)" env:"USE_HOST_IP"`
LabelSelector string `long:"label-selector" description:"label selector to use to discover goldpinger pods in the cluster" env:"LABEL_SELECTOR" default:"app=goldpinger"`
KubernetesClient *kubernetes.Clientset
*PodSelecter
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:" "`
// 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"`
}{}

View File

@@ -18,15 +18,17 @@ package goldpinger
import (
"bytes"
"context"
"fmt"
"image"
"image/color"
"image/png"
"log"
"net/http"
"sort"
"strconv"
"time"
"go.uber.org/zap"
"golang.org/x/image/font"
"golang.org/x/image/font/basicfont"
"golang.org/x/image/math/fixed"
@@ -79,8 +81,14 @@ func HeatmapHandler(w http.ResponseWriter, r *http.Request) {
// parse the query to set the parameters
query := r.URL.Query()
ctx, cancel := context.WithTimeout(
r.Context(),
time.Duration(GoldpingerConfig.CheckAllTimeoutMs)*time.Millisecond,
)
defer cancel()
// get the results
checkResults := CheckAllPods(GetAllPods())
checkResults := CheckAllPods(ctx, GetAllPods())
// set some sizes
numberOfPods := len(checkResults.Responses)
@@ -135,12 +143,12 @@ func HeatmapHandler(w http.ResponseWriter, r *http.Request) {
buffer := new(bytes.Buffer)
if err := png.Encode(buffer, canvas); err != nil {
log.Println("error encoding png", err)
zap.L().Error("error encoding png", zap.Error(err))
}
w.Header().Set("Content-Type", "image/png")
w.Header().Set("Content-Length", strconv.Itoa(len(buffer.Bytes())))
if _, err := w.Write(buffer.Bytes()); err != nil {
log.Println("error writing heatmap buffer out", err)
zap.L().Error("error writing heatmap buffer out", zap.Error(err))
}
}

View File

@@ -15,35 +15,50 @@
package goldpinger
import (
"log"
"io/ioutil"
"go.uber.org/zap"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// namespace is the namespace for the goldpinger pod
var namespace = getNamespace()
// GoldpingerPod contains just the basic info needed to ping and keep track of a given goldpinger pod
type GoldpingerPod struct {
Name string // Name is the name of the pod
PodIP string // PodIP is the IP address of the pod
HostIP string // HostIP is the IP address of the host where the pod lives
}
func getNamespace() string {
b, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace")
if err != nil {
log.Println("Unable to determine namespace: ", err.Error())
zap.L().Warn("Unable to determine namespace", zap.Error(err))
return ""
}
namespace := string(b)
return namespace
}
// GetAllPods returns a map of Pod IP to Host IP based on a label selector defined in config
func GetAllPods() map[string]string {
// GetAllPods returns a mapping from a pod name to a pointer to a GoldpingerPod(s)
func GetAllPods() map[string]*GoldpingerPod {
timer := GetLabeledKubernetesCallsTimer()
pods, err := GoldpingerConfig.KubernetesClient.CoreV1().Pods(getNamespace()).List(metav1.ListOptions{LabelSelector: GoldpingerConfig.LabelSelector})
pods, err := GoldpingerConfig.KubernetesClient.CoreV1().Pods(namespace).List(metav1.ListOptions{LabelSelector: GoldpingerConfig.LabelSelector})
if err != nil {
log.Println("Error getting pods for selector: ", err.Error())
zap.L().Error("Error getting pods for selector", zap.String("selector", GoldpingerConfig.LabelSelector), zap.Error(err))
CountError("kubernetes_api")
} else {
timer.ObserveDuration()
}
var podsreturn = make(map[string]string)
var podMap = make(map[string]*GoldpingerPod)
for _, pod := range pods.Items {
podsreturn[pod.Status.PodIP] = pod.Status.HostIP
podMap[pod.Name] = &GoldpingerPod{
Name: pod.Name,
PodIP: pod.Status.PodIP,
HostIP: pod.Status.HostIP,
}
}
return podsreturn
return podMap
}

176
pkg/goldpinger/pinger.go Normal file
View File

@@ -0,0 +1,176 @@
// 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"
"time"
"go.uber.org/zap"
apiclient "github.com/bloomberg/goldpinger/v3/pkg/client"
"github.com/bloomberg/goldpinger/v3/pkg/client/operations"
"github.com/bloomberg/goldpinger/v3/pkg/models"
"github.com/go-openapi/strfmt"
"github.com/prometheus/client_golang/prometheus"
"k8s.io/apimachinery/pkg/util/wait"
)
// Pinger contains all the info needed by a goroutine to continuously ping a pod
type Pinger struct {
pod *GoldpingerPod
client *apiclient.Goldpinger
timeout time.Duration
histogram prometheus.Observer
hostIPv4 strfmt.IPv4
podIPv4 strfmt.IPv4
resultsChan chan<- PingAllPodsResult
stopChan chan struct{}
logger *zap.Logger
}
// NewPinger constructs and returns a Pinger object responsible for pinging a single
// goldpinger pod
func NewPinger(pod *GoldpingerPod, resultsChan chan<- PingAllPodsResult) *Pinger {
p := Pinger{
pod: pod,
timeout: time.Duration(GoldpingerConfig.PingTimeoutMs) * time.Millisecond,
resultsChan: resultsChan,
stopChan: make(chan struct{}),
histogram: goldpingerResponseTimePeersHistogram.WithLabelValues(
GoldpingerConfig.Hostname,
"ping",
pod.HostIP,
pod.PodIP,
),
logger: zap.L().With(
zap.String("op", "pinger"),
zap.String("name", pod.Name),
zap.String("hostIP", pod.HostIP),
zap.String("podIP", pod.PodIP),
),
}
// Initialize the host/pod IPv4
p.hostIPv4.UnmarshalText([]byte(pod.HostIP))
p.podIPv4.UnmarshalText([]byte(pod.PodIP))
return &p
}
// getClient returns a client that can be used to ping the given pod
// On error, it returns a static result
func (p *Pinger) getClient() (*apiclient.Goldpinger, error) {
if p.client != nil {
return p.client, nil
}
client, err := getClient(pickPodHostIP(p.pod.PodIP, p.pod.HostIP))
if err != nil {
p.logger.Warn("Could not get client", zap.Error(err))
OK := false
p.resultsChan <- PingAllPodsResult{
podName: p.pod.Name,
podResult: models.PodResult{
PingTime: strfmt.DateTime(time.Now()),
PodIP: p.podIPv4,
HostIP: p.hostIPv4,
OK: &OK,
Error: err.Error(),
StatusCode: 500,
ResponseTimeMs: 0,
},
}
return nil, err
}
p.client = client
return p.client, nil
}
// Ping makes a single ping request to the given pod
func (p *Pinger) Ping() {
client, err := p.getClient()
if err != nil {
return
}
CountCall("made", "ping")
start := time.Now()
ctx, cancel := context.WithTimeout(context.Background(), p.timeout)
defer cancel()
params := operations.NewPingParamsWithContext(ctx)
resp, err := client.Operations.Ping(params)
responseTime := time.Since(start)
responseTimeMs := responseTime.Nanoseconds() / int64(time.Millisecond)
p.histogram.Observe(responseTime.Seconds())
OK := (err == nil)
if OK {
p.resultsChan <- PingAllPodsResult{
podName: p.pod.Name,
podResult: models.PodResult{
PingTime: strfmt.DateTime(start),
PodIP: p.podIPv4,
HostIP: p.hostIPv4,
OK: &OK,
Response: resp.Payload,
StatusCode: 200,
ResponseTimeMs: responseTimeMs,
},
}
p.logger.Debug("Success pinging pod", zap.Duration("responseTime", responseTime))
} else {
p.resultsChan <- PingAllPodsResult{
podName: p.pod.Name,
podResult: models.PodResult{
PingTime: strfmt.DateTime(start),
PodIP: p.podIPv4,
HostIP: p.hostIPv4,
OK: &OK,
Error: err.Error(),
StatusCode: 504,
ResponseTimeMs: responseTimeMs,
},
}
p.logger.Warn("Ping returned error", zap.Duration("responseTime", responseTime), zap.Error(err))
CountError("ping")
}
}
// PingContinuously continuously pings the given pod with a delay between
// `period` and `period + jitterFactor * period`
func (p *Pinger) PingContinuously(initialWait time.Duration, period time.Duration, jitterFactor float64) {
p.logger.Info(
"Starting pinger",
zap.Duration("period", period),
zap.Duration("initialWait", initialWait),
zap.Float64("jitterFactor", jitterFactor),
)
timer := time.NewTimer(initialWait)
select {
case <-timer.C:
wait.JitterUntil(p.Ping, period, jitterFactor, false, p.stopChan)
case <-p.stopChan:
// Do nothing
}
// We are done, send a message on the results channel to delete this
p.resultsChan <- PingAllPodsResult{podName: p.pod.Name, deleted: true}
}

View File

@@ -19,43 +19,22 @@ import (
rendezvous "github.com/stuartnelson3/go-rendezvous"
)
// PodSelecter selects the result of getPods() down to count instances
// according to a rendezvous hash.
type PodSelecter struct {
count uint
podIP string
getPods func() map[string]string
}
// NewPodSelecter creates a new PodSelecter struct.
func NewPodSelecter(count uint, podIP string, getPods func() map[string]string) *PodSelecter {
if podIP == "" {
// If podIP is blank, then we can't use the rendezvous hash to
// assign the IP correctly. Setting count=0 will force all pods
// to be pinged.
count = 0
}
return &PodSelecter{
count: count,
podIP: podIP,
getPods: getPods,
}
}
// SelectPods returns a map of pods filtered according to its configuration.
func (p *PodSelecter) SelectPods() map[string]string {
allPods := p.getPods()
if p.count == 0 || p.count >= uint(len(allPods)) {
// SelectPods selects a set of pods from the results of GetAllPods
// depending on the count according to a rendezvous hash
func SelectPods() map[string]*GoldpingerPod {
allPods := GetAllPods()
if GoldpingerConfig.PingNumber <= 0 || int(GoldpingerConfig.PingNumber) >= len(allPods) {
return allPods
}
rzv := rendezvous.New([]string{}, rendezvous.Hasher(xxhash.Sum64String))
for podIP := range allPods {
rzv.Add(podIP)
for podName := range allPods {
rzv.Add(podName)
}
matches := rzv.LookupN(p.podIP, p.count)
toPing := make(map[string]string)
for _, podIP := range matches {
toPing[podIP] = allPods[podIP]
matches := rzv.LookupN(GoldpingerConfig.PodName, GoldpingerConfig.PingNumber)
toPing := make(map[string]*GoldpingerPod)
for _, podName := range matches {
toPing[podName] = allPods[podName]
}
return toPing
}

View File

@@ -15,12 +15,13 @@
package goldpinger
import (
"log"
"context"
"time"
"github.com/bloomberg/goldpinger/pkg/models"
"github.com/bloomberg/goldpinger/v3/pkg/models"
"github.com/go-openapi/strfmt"
"github.com/prometheus/client_golang/prometheus"
"go.uber.org/zap"
)
var (
@@ -103,10 +104,10 @@ func init() {
prometheus.MustRegister(goldpingerResponseTimeKubernetesHistogram)
prometheus.MustRegister(goldpingerErrorsCounter)
prometheus.MustRegister(goldpingerDnsErrorsCounter)
log.Println("Metrics setup - see /metrics")
zap.L().Info("Metrics setup - see /metrics")
}
func GetStats() *models.PingResults {
func GetStats(ctx context.Context) *models.PingResults {
// GetStats no longer populates the received and made calls - use metrics for that instead
return &models.PingResults{
BootTime: strfmt.DateTime(bootTime),

View File

@@ -15,31 +15,179 @@
package goldpinger
import (
"fmt"
"log"
"sync"
"time"
"go.uber.org/zap"
"github.com/bloomberg/goldpinger/v3/pkg/models"
)
// checkResults holds the latest results of checking the pods
var checkResults = models.CheckResults{PodResults: make(map[string]models.PodResult)}
// checkResultsMux controls concurrent access to checkResults
var checkResultsMux = sync.Mutex{}
// exists checks whether there is an existing pinger for the given pod
// returns true if:
// - 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]
return exists && (old.PodIP == new.PodIP) && (old.HostIP == new.HostIP)
}
// updatePingers calls SelectPods() at regular intervals to get a new list of goldpinger pods to ping
// For each goldpinger pod, it then creates a pinger responsible for pinging it and returning the
// results on the result channel
func updatePingers(resultsChan chan<- PingAllPodsResult) {
// Important: This is the only goroutine that should have access to
// these maps since there is nothing controlling concurrent access
pingers := make(map[string]*Pinger)
existingPods := make(map[string]*GoldpingerPod)
refreshPeriod := time.Duration(GoldpingerConfig.RefreshInterval) * time.Second
for {
// Initialize deletedPods to all existing pods, we will remove
// any pods that should still exist from this list after we are done
// NOTE: This is *NOT* a copy of existingPods just a new variable name
// to make the intention/code clear and cleaner
deletedPods := existingPods
// New pods are brand new and haven't been seen before
newPods := make(map[string]*GoldpingerPod)
latest := SelectPods()
for podName, pod := range latest {
if exists(existingPods, 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
delete(deletedPods, podName)
} else {
// This pod is brand new and has never been seen before
// Add it to the list of newPods
newPods[podName] = pod
}
}
// deletedPods now contains any pods that have either been deleted from the api-server
// *OR* weren't selected by our rendezvous hash
// *OR* had their host/pod IP changed. Remove those pingers
destroyPingers(pingers, deletedPods)
// Next create pingers for new pods
createPingers(pingers, newPods, resultsChan, refreshPeriod)
// Finally, just set existingPods to the latest and collect garbage
existingPods = latest
deletedPods = nil
newPods = nil
// Wait the given time before pinging
time.Sleep(refreshPeriod)
}
}
// createPingers allocates a new pinger object for each new goldpinger Pod that's been discovered
// It also:
// (a) initializes a result object in checkResults to store info on that pod
// (b) starts a new goroutines to continuously ping the given pod.
// Each new goroutine waits for a given time before starting the continuous ping
// to prevent a thundering herd
func createPingers(pingers map[string]*Pinger, newPods map[string]*GoldpingerPod, resultsChan chan<- PingAllPodsResult, refreshPeriod time.Duration) {
if len(newPods) == 0 {
// I have nothing to do
return
}
waitBetweenPods := refreshPeriod / time.Duration(len(newPods))
zap.L().Info(
"Starting pingers for new pods",
zap.Int("numNewPods", len(newPods)),
zap.Duration("refreshPeriod", refreshPeriod),
zap.Duration("waitPeriod", waitBetweenPods),
zap.Float64("JitterFactor", GoldpingerConfig.JitterFactor),
)
initialWait := time.Duration(0)
for podName, pod := range newPods {
pinger := NewPinger(pod, resultsChan)
pingers[podName] = pinger
go pinger.PingContinuously(initialWait, refreshPeriod, GoldpingerConfig.JitterFactor)
initialWait += waitBetweenPods
}
}
// destroyPingers takes a list of deleted pods and then for each pod in the list, it stops
// the goroutines that continuously pings that pod and then deletes the pod from the list of pingers
func destroyPingers(pingers map[string]*Pinger, deletedPods map[string]*GoldpingerPod) {
for podName, pod := range deletedPods {
zap.L().Info(
"Deleting pod from pingers",
zap.String("name", podName),
zap.String("podIP", pod.PodIP),
zap.String("hostIP", pod.HostIP),
)
pinger := pingers[podName]
// Close the channel to stop pinging
close(pinger.stopChan)
// delete from pingers
delete(pingers, podName)
}
}
// updateCounters updates the count of health and unhealthy nodes
func updateCounters() {
checkResultsMux.Lock()
defer checkResultsMux.Unlock()
var counterHealthy float64
for _, result := range checkResults.PodResults {
if result.OK != nil && *result.OK {
counterHealthy++
}
}
CountHealthyUnhealthyNodes(counterHealthy, float64(len(checkResults.PodResults))-counterHealthy)
}
// collectResults simply reads results from the results channel and saves them in a map
func collectResults(resultsChan <-chan PingAllPodsResult) {
refreshPeriod := time.Duration(GoldpingerConfig.RefreshInterval) * time.Second
updateTicker := time.NewTicker(refreshPeriod)
for {
select {
case <-updateTicker.C:
// Every time our update ticker ticks, update the count of healthy/unhealthy nodes
updateCounters()
case response := <-resultsChan:
// On getting a ping response, if the pinger is not being deleted,
// simply save it for later
checkResultsMux.Lock()
if response.deleted {
delete(checkResults.PodResults, response.podName)
} else {
checkResults.PodResults[response.podName] = response.podResult
}
checkResultsMux.Unlock()
}
}
}
func StartUpdater() {
if GoldpingerConfig.RefreshInterval <= 0 {
log.Println("Not creating updater, period is 0")
zap.L().Info("Not creating updater, refresh interval is negative", zap.Int("RefreshInterval", GoldpingerConfig.RefreshInterval))
return
}
// start the updater
go func() {
for {
results := PingAllPods(GoldpingerConfig.PodSelecter.SelectPods())
var troublemakers []string
for podIP, value := range results.PodResults {
if *value.OK != true {
troublemakers = append(troublemakers, fmt.Sprintf("%s (%s)", podIP, value.HostIP.String()))
}
}
if len(troublemakers) > 0 {
log.Println("Updater ran into trouble with these peers: ", troublemakers)
}
time.Sleep(time.Duration(GoldpingerConfig.RefreshInterval) * time.Second)
}
}()
pods := SelectPods()
// Create a channel for the results
resultsChan := make(chan PingAllPodsResult, len(pods))
go updatePingers(resultsChan)
go collectResults(resultsChan)
}

View File

@@ -6,12 +6,12 @@ package models
// Editing this file might prove futile when you re-run the swagger generate command
import (
strfmt "github.com/go-openapi/strfmt"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// CallStats call stats
//
// swagger:model CallStats
type CallStats struct {

View File

@@ -6,14 +6,14 @@ package models
// Editing this file might prove futile when you re-run the swagger generate command
import (
strfmt "github.com/go-openapi/strfmt"
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// CheckAllPodResult check all pod result
//
// swagger:model CheckAllPodResult
type CheckAllPodResult struct {
@@ -24,6 +24,10 @@ type CheckAllPodResult struct {
// o k
OK *bool `json:"OK,omitempty"`
// pod IP
// Format: ipv4
PodIP strfmt.IPv4 `json:"PodIP,omitempty"`
// error
Error string `json:"error,omitempty"`
@@ -42,6 +46,10 @@ func (m *CheckAllPodResult) Validate(formats strfmt.Registry) error {
res = append(res, err)
}
if err := m.validatePodIP(formats); err != nil {
res = append(res, err)
}
if err := m.validateResponse(formats); err != nil {
res = append(res, err)
}
@@ -65,6 +73,19 @@ func (m *CheckAllPodResult) validateHostIP(formats strfmt.Registry) error {
return nil
}
func (m *CheckAllPodResult) validatePodIP(formats strfmt.Registry) error {
if swag.IsZero(m.PodIP) { // not required
return nil
}
if err := validate.FormatOf("PodIP", "body", "ipv4", m.PodIP.String(), formats); err != nil {
return err
}
return nil
}
func (m *CheckAllPodResult) validateResponse(formats strfmt.Registry) error {
if swag.IsZero(m.Response) { // not required

View File

@@ -8,14 +8,14 @@ package models
import (
"strconv"
strfmt "github.com/go-openapi/strfmt"
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// CheckAllResults check all results
//
// swagger:model CheckAllResults
type CheckAllResults struct {
@@ -145,6 +145,7 @@ func (m *CheckAllResults) UnmarshalBinary(b []byte) error {
}
// CheckAllResultsHostsItems0 check all results hosts items0
//
// swagger:model CheckAllResultsHostsItems0
type CheckAllResultsHostsItems0 struct {
@@ -155,6 +156,9 @@ type CheckAllResultsHostsItems0 struct {
// pod IP
// Format: ipv4
PodIP strfmt.IPv4 `json:"podIP,omitempty"`
// pod name
PodName string `json:"podName,omitempty"`
}
// Validate validates this check all results hosts items0

View File

@@ -6,14 +6,14 @@ package models
// Editing this file might prove futile when you re-run the swagger generate command
import (
strfmt "github.com/go-openapi/strfmt"
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// CheckResults check results
//
// swagger:model CheckResults
type CheckResults struct {

View File

@@ -6,12 +6,12 @@ package models
// Editing this file might prove futile when you re-run the swagger generate command
import (
strfmt "github.com/go-openapi/strfmt"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// DNSResult Dns result
//
// swagger:model DnsResult
type DNSResult struct {

View File

@@ -6,13 +6,13 @@ package models
// Editing this file might prove futile when you re-run the swagger generate command
import (
strfmt "github.com/go-openapi/strfmt"
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/validate"
)
// DNSResults Dns results
//
// swagger:model DnsResults
type DNSResults map[string]DNSResult

View File

@@ -6,14 +6,14 @@ package models
// Editing this file might prove futile when you re-run the swagger generate command
import (
strfmt "github.com/go-openapi/strfmt"
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// HealthCheckResults health check results
//
// swagger:model HealthCheckResults
type HealthCheckResults struct {

View File

@@ -6,14 +6,14 @@ package models
// Editing this file might prove futile when you re-run the swagger generate command
import (
strfmt "github.com/go-openapi/strfmt"
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// PingResults ping results
//
// swagger:model PingResults
type PingResults struct {

View File

@@ -6,14 +6,14 @@ package models
// Editing this file might prove futile when you re-run the swagger generate command
import (
strfmt "github.com/go-openapi/strfmt"
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// PodResult pod result
//
// swagger:model PodResult
type PodResult struct {
@@ -24,6 +24,14 @@ type PodResult struct {
// o k
OK *bool `json:"OK,omitempty"`
// ping time
// Format: date-time
PingTime strfmt.DateTime `json:"PingTime,omitempty"`
// pod IP
// Format: ipv4
PodIP strfmt.IPv4 `json:"PodIP,omitempty"`
// error
Error string `json:"error,omitempty"`
@@ -45,6 +53,14 @@ func (m *PodResult) Validate(formats strfmt.Registry) error {
res = append(res, err)
}
if err := m.validatePingTime(formats); err != nil {
res = append(res, err)
}
if err := m.validatePodIP(formats); err != nil {
res = append(res, err)
}
if err := m.validateResponse(formats); err != nil {
res = append(res, err)
}
@@ -68,6 +84,32 @@ func (m *PodResult) validateHostIP(formats strfmt.Registry) error {
return nil
}
func (m *PodResult) validatePingTime(formats strfmt.Registry) error {
if swag.IsZero(m.PingTime) { // not required
return nil
}
if err := validate.FormatOf("PingTime", "body", "date-time", m.PingTime.String(), formats); err != nil {
return err
}
return nil
}
func (m *PodResult) validatePodIP(formats strfmt.Registry) error {
if swag.IsZero(m.PodIP) { // not required
return nil
}
if err := validate.FormatOf("PodIP", "body", "ipv4", m.PodIP.String(), formats); err != nil {
return err
}
return nil
}
func (m *PodResult) validateResponse(formats strfmt.Registry) error {
if swag.IsZero(m.Response) { // not required

View File

@@ -17,18 +17,20 @@
package restapi
import (
"context"
"crypto/tls"
"log"
"net/http"
"time"
"strings"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
"github.com/go-openapi/runtime/middleware"
"go.uber.org/zap"
"github.com/bloomberg/goldpinger/pkg/goldpinger"
"github.com/bloomberg/goldpinger/pkg/restapi/operations"
"github.com/bloomberg/goldpinger/v3/pkg/goldpinger"
"github.com/bloomberg/goldpinger/v3/pkg/restapi/operations"
"github.com/go-openapi/swag"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
@@ -47,7 +49,7 @@ func configureFlags(api *operations.GoldpingerAPI) {
func configureAPI(api *operations.GoldpingerAPI) http.Handler {
// configure the api here
ps := goldpinger.GoldpingerConfig.PodSelecter
api.Logger = zap.S().Infof
api.ServeError = errors.ServeError
api.JSONConsumer = runtime.JSONConsumer()
@@ -56,19 +58,40 @@ func configureAPI(api *operations.GoldpingerAPI) http.Handler {
api.PingHandler = operations.PingHandlerFunc(
func(params operations.PingParams) middleware.Responder {
goldpinger.CountCall("received", "ping")
return operations.NewPingOK().WithPayload(goldpinger.GetStats())
ctx, cancel := context.WithTimeout(
params.HTTPRequest.Context(),
time.Duration(goldpinger.GoldpingerConfig.PingTimeoutMs)*time.Millisecond,
)
defer cancel()
return operations.NewPingOK().WithPayload(goldpinger.GetStats(ctx))
})
api.CheckServicePodsHandler = operations.CheckServicePodsHandlerFunc(
func(params operations.CheckServicePodsParams) middleware.Responder {
goldpinger.CountCall("received", "check")
return operations.NewCheckServicePodsOK().WithPayload(goldpinger.CheckNeighbours(ps))
ctx, cancel := context.WithTimeout(
params.HTTPRequest.Context(),
time.Duration(goldpinger.GoldpingerConfig.CheckTimeoutMs)*time.Millisecond,
)
defer cancel()
return operations.NewCheckServicePodsOK().WithPayload(goldpinger.CheckNeighbours(ctx))
})
api.CheckAllPodsHandler = operations.CheckAllPodsHandlerFunc(
func(params operations.CheckAllPodsParams) middleware.Responder {
goldpinger.CountCall("received", "check_all")
return operations.NewCheckAllPodsOK().WithPayload(goldpinger.CheckNeighboursNeighbours(ps))
ctx, cancel := context.WithTimeout(
params.HTTPRequest.Context(),
time.Duration(goldpinger.GoldpingerConfig.CheckAllTimeoutMs)*time.Millisecond,
)
defer cancel()
return operations.NewCheckAllPodsOK().WithPayload(goldpinger.CheckNeighboursNeighbours(ctx))
})
api.HealthzHandler = operations.HealthzHandlerFunc(
@@ -106,7 +129,7 @@ func setupMiddlewares(handler http.Handler) http.Handler {
}
func fileServerMiddleware(next http.Handler) http.Handler {
log.Println("Added the static middleware")
zap.L().Info("Added the static middleware")
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fileServer := http.FileServer(http.Dir(goldpinger.GoldpingerConfig.StaticFilePath))
if r.URL.Path == "/" {
@@ -123,7 +146,7 @@ func fileServerMiddleware(next http.Handler) http.Handler {
}
func prometheusMetricsMiddleware(next http.Handler) http.Handler {
log.Println("Added the prometheus middleware")
zap.L().Info("Added the prometheus middleware")
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/metrics" {
http.StripPrefix("/metrics", promhttp.Handler()).ServeHTTP(w, r)

View File

@@ -1,20 +1,18 @@
// Code generated by go-swagger; DO NOT EDIT.
/*
Package restapi Goldpinger
Schemes:
http
Host: localhost
BasePath: /
Version: 2.0.0
Consumes:
- application/json
Produces:
- application/json
swagger:meta
*/
// Package restapi Goldpinger
//
// Schemes:
// http
// Host: localhost
// BasePath: /
// Version: 3.0.0
//
// Consumes:
// - application/json
//
// Produces:
// - application/json
//
// swagger:meta
package restapi

View File

@@ -21,7 +21,7 @@ func init() {
"swagger": "2.0",
"info": {
"title": "Goldpinger",
"version": "2.0.0"
"version": "3.0.0"
},
"paths": {
"/check": {
@@ -124,6 +124,10 @@ func init() {
"type": "boolean",
"default": false
},
"PodIP": {
"type": "string",
"format": "ipv4"
},
"error": {
"type": "string"
},
@@ -161,6 +165,9 @@ func init() {
"podIP": {
"type": "string",
"format": "ipv4"
},
"podName": {
"type": "string"
}
}
}
@@ -252,6 +259,14 @@ func init() {
"type": "boolean",
"default": false
},
"PingTime": {
"type": "string",
"format": "date-time"
},
"PodIP": {
"type": "string",
"format": "ipv4"
},
"error": {
"type": "string"
},
@@ -275,7 +290,7 @@ func init() {
"swagger": "2.0",
"info": {
"title": "Goldpinger",
"version": "2.0.0"
"version": "3.0.0"
},
"paths": {
"/check": {
@@ -378,6 +393,10 @@ func init() {
"type": "boolean",
"default": false
},
"PodIP": {
"type": "string",
"format": "ipv4"
},
"error": {
"type": "string"
},
@@ -406,17 +425,7 @@ func init() {
"hosts": {
"type": "array",
"items": {
"type": "object",
"properties": {
"hostIP": {
"type": "string",
"format": "ipv4"
},
"podIP": {
"type": "string",
"format": "ipv4"
}
}
"$ref": "#/definitions/CheckAllResultsHostsItems0"
}
},
"hosts-healthy": {
@@ -435,6 +444,22 @@ func init() {
}
}
},
"CheckAllResultsHostsItems0": {
"type": "object",
"properties": {
"hostIP": {
"type": "string",
"format": "ipv4"
},
"podIP": {
"type": "string",
"format": "ipv4"
},
"podName": {
"type": "string"
}
}
},
"CheckResults": {
"type": "object",
"properties": {
@@ -506,6 +531,14 @@ func init() {
"type": "boolean",
"default": false
},
"PingTime": {
"type": "string",
"format": "date-time"
},
"PodIP": {
"type": "string",
"format": "ipv4"
},
"error": {
"type": "string"
},

View File

@@ -8,7 +8,7 @@ package operations
import (
"net/http"
middleware "github.com/go-openapi/runtime/middleware"
"github.com/go-openapi/runtime/middleware"
)
// CheckAllPodsHandlerFunc turns a function with the right signature into a check all pods handler

View File

@@ -10,7 +10,7 @@ import (
"github.com/go-openapi/runtime"
models "github.com/bloomberg/goldpinger/pkg/models"
"github.com/bloomberg/goldpinger/v3/pkg/models"
)
// CheckAllPodsOKCode is the HTTP code returned for type CheckAllPodsOK

View File

@@ -8,7 +8,7 @@ package operations
import (
"net/http"
middleware "github.com/go-openapi/runtime/middleware"
"github.com/go-openapi/runtime/middleware"
)
// CheckServicePodsHandlerFunc turns a function with the right signature into a check service pods handler

View File

@@ -10,7 +10,7 @@ import (
"github.com/go-openapi/runtime"
models "github.com/bloomberg/goldpinger/pkg/models"
"github.com/bloomberg/goldpinger/v3/pkg/models"
)
// CheckServicePodsOKCode is the HTTP code returned for type CheckServicePodsOK

View File

@@ -10,13 +10,13 @@ import (
"net/http"
"strings"
errors "github.com/go-openapi/errors"
loads "github.com/go-openapi/loads"
runtime "github.com/go-openapi/runtime"
middleware "github.com/go-openapi/runtime/middleware"
security "github.com/go-openapi/runtime/security"
spec "github.com/go-openapi/spec"
strfmt "github.com/go-openapi/strfmt"
"github.com/go-openapi/errors"
"github.com/go-openapi/loads"
"github.com/go-openapi/runtime"
"github.com/go-openapi/runtime/middleware"
"github.com/go-openapi/runtime/security"
"github.com/go-openapi/spec"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
@@ -29,14 +29,18 @@ func NewGoldpingerAPI(spec *loads.Document) *GoldpingerAPI {
defaultProduces: "application/json",
customConsumers: make(map[string]runtime.Consumer),
customProducers: make(map[string]runtime.Producer),
PreServerShutdown: func() {},
ServerShutdown: func() {},
spec: spec,
ServeError: errors.ServeError,
BasicAuthenticator: security.BasicAuth,
APIKeyAuthenticator: security.APIKeyAuth,
BearerAuthenticator: security.BearerAuth,
JSONConsumer: runtime.JSONConsumer(),
JSONProducer: runtime.JSONProducer(),
JSONConsumer: runtime.JSONConsumer(),
JSONProducer: runtime.JSONProducer(),
CheckAllPodsHandler: CheckAllPodsHandlerFunc(func(params CheckAllPodsParams) middleware.Responder {
return middleware.NotImplemented("operation CheckAllPods has not yet been implemented")
}),
@@ -74,10 +78,12 @@ type GoldpingerAPI struct {
// It has a default implementation in the security package, however you can replace it for your particular usage.
BearerAuthenticator func(string, security.ScopedTokenAuthentication) runtime.Authenticator
// JSONConsumer registers a consumer for a "application/json" mime type
// JSONConsumer registers a consumer for the following mime types:
// - application/json
JSONConsumer runtime.Consumer
// JSONProducer registers a producer for a "application/json" mime type
// JSONProducer registers a producer for the following mime types:
// - application/json
JSONProducer runtime.Producer
// CheckAllPodsHandler sets the operation handler for the check all pods operation
@@ -88,11 +94,14 @@ type GoldpingerAPI struct {
HealthzHandler HealthzHandler
// PingHandler sets the operation handler for the ping operation
PingHandler PingHandler
// ServeError is called when an error is received, there is a default handler
// but you can set your own with this
ServeError func(http.ResponseWriter, *http.Request, error)
// PreServerShutdown is called before the HTTP(S) server is shutdown
// This allows for custom functions to get executed before the HTTP(S) server stops accepting traffic
PreServerShutdown func()
// ServerShutdown is called when the HTTP(S) server is shut down and done
// handling all active connections and does not accept connections any more
ServerShutdown func()
@@ -154,15 +163,12 @@ func (o *GoldpingerAPI) Validate() error {
if o.CheckAllPodsHandler == nil {
unregistered = append(unregistered, "CheckAllPodsHandler")
}
if o.CheckServicePodsHandler == nil {
unregistered = append(unregistered, "CheckServicePodsHandler")
}
if o.HealthzHandler == nil {
unregistered = append(unregistered, "HealthzHandler")
}
if o.PingHandler == nil {
unregistered = append(unregistered, "PingHandler")
}
@@ -181,28 +187,22 @@ func (o *GoldpingerAPI) ServeErrorFor(operationID string) func(http.ResponseWrit
// AuthenticatorsFor gets the authenticators for the specified security schemes
func (o *GoldpingerAPI) AuthenticatorsFor(schemes map[string]spec.SecurityScheme) map[string]runtime.Authenticator {
return nil
}
// Authorizer returns the registered authorizer
func (o *GoldpingerAPI) Authorizer() runtime.Authorizer {
return nil
}
// ConsumersFor gets the consumers for the specified media types
// ConsumersFor gets the consumers for the specified media types.
// MIME type parameters are ignored here.
func (o *GoldpingerAPI) ConsumersFor(mediaTypes []string) map[string]runtime.Consumer {
result := make(map[string]runtime.Consumer)
result := make(map[string]runtime.Consumer, len(mediaTypes))
for _, mt := range mediaTypes {
switch mt {
case "application/json":
result["application/json"] = o.JSONConsumer
}
if c, ok := o.customConsumers[mt]; ok {
@@ -210,19 +210,16 @@ func (o *GoldpingerAPI) ConsumersFor(mediaTypes []string) map[string]runtime.Con
}
}
return result
}
// ProducersFor gets the producers for the specified media types
// ProducersFor gets the producers for the specified media types.
// MIME type parameters are ignored here.
func (o *GoldpingerAPI) ProducersFor(mediaTypes []string) map[string]runtime.Producer {
result := make(map[string]runtime.Producer)
result := make(map[string]runtime.Producer, len(mediaTypes))
for _, mt := range mediaTypes {
switch mt {
case "application/json":
result["application/json"] = o.JSONProducer
}
if p, ok := o.customProducers[mt]; ok {
@@ -230,7 +227,6 @@ func (o *GoldpingerAPI) ProducersFor(mediaTypes []string) map[string]runtime.Pro
}
}
return result
}
// HandlerFor gets a http.Handler for the provided operation method and path
@@ -260,7 +256,6 @@ func (o *GoldpingerAPI) Context() *middleware.Context {
func (o *GoldpingerAPI) initHandlerCache() {
o.Context() // don't care about the result, just that the initialization happened
if o.handlers == nil {
o.handlers = make(map[string]map[string]http.Handler)
}
@@ -269,22 +264,18 @@ func (o *GoldpingerAPI) initHandlerCache() {
o.handlers["GET"] = make(map[string]http.Handler)
}
o.handlers["GET"]["/check_all"] = NewCheckAllPods(o.context, o.CheckAllPodsHandler)
if o.handlers["GET"] == nil {
o.handlers["GET"] = make(map[string]http.Handler)
}
o.handlers["GET"]["/check"] = NewCheckServicePods(o.context, o.CheckServicePodsHandler)
if o.handlers["GET"] == nil {
o.handlers["GET"] = make(map[string]http.Handler)
}
o.handlers["GET"]["/healthz"] = NewHealthz(o.context, o.HealthzHandler)
if o.handlers["GET"] == nil {
o.handlers["GET"] = make(map[string]http.Handler)
}
o.handlers["GET"]["/ping"] = NewPing(o.context, o.PingHandler)
}
// Serve creates a http handler to serve the API over HTTP
@@ -314,3 +305,15 @@ func (o *GoldpingerAPI) RegisterConsumer(mediaType string, consumer runtime.Cons
func (o *GoldpingerAPI) RegisterProducer(mediaType string, producer runtime.Producer) {
o.customProducers[mediaType] = producer
}
// AddMiddlewareFor adds a http middleware to existing handler
func (o *GoldpingerAPI) AddMiddlewareFor(method, path string, builder middleware.Builder) {
um := strings.ToUpper(method)
if path == "/" {
path = ""
}
o.Init()
if h, ok := o.handlers[um][path]; ok {
o.handlers[method][path] = builder(h)
}
}

View File

@@ -8,7 +8,7 @@ package operations
import (
"net/http"
middleware "github.com/go-openapi/runtime/middleware"
"github.com/go-openapi/runtime/middleware"
)
// HealthzHandlerFunc turns a function with the right signature into a healthz handler

View File

@@ -10,7 +10,7 @@ import (
"github.com/go-openapi/runtime"
models "github.com/bloomberg/goldpinger/pkg/models"
"github.com/bloomberg/goldpinger/v3/pkg/models"
)
// HealthzOKCode is the HTTP code returned for type HealthzOK

View File

@@ -8,7 +8,7 @@ package operations
import (
"net/http"
middleware "github.com/go-openapi/runtime/middleware"
"github.com/go-openapi/runtime/middleware"
)
// PingHandlerFunc turns a function with the right signature into a ping handler

View File

@@ -10,7 +10,7 @@ import (
"github.com/go-openapi/runtime"
models "github.com/bloomberg/goldpinger/pkg/models"
"github.com/bloomberg/goldpinger/v3/pkg/models"
)
// PingOKCode is the HTTP code returned for type PingOK

View File

@@ -25,7 +25,7 @@ import (
flags "github.com/jessevdk/go-flags"
"golang.org/x/net/netutil"
"github.com/bloomberg/goldpinger/pkg/restapi/operations"
"github.com/bloomberg/goldpinger/v3/pkg/restapi/operations"
)
const (
@@ -133,7 +133,6 @@ func (s *Server) SetAPI(api *operations.GoldpingerAPI) {
}
s.api = api
s.api.Logger = log.Printf
s.handler = configureAPI(api)
}
@@ -174,8 +173,6 @@ func (s *Server) Serve() (err error) {
go handleInterrupt(once, s)
servers := []*http.Server{}
wg.Add(1)
go s.handleShutdown(wg, &servers)
if s.hasScheme(schemeUnix) {
domainSocket := new(http.Server)
@@ -252,7 +249,7 @@ func (s *Server) Serve() (err error) {
// https://github.com/golang/go/tree/master/src/crypto/elliptic
CurvePreferences: []tls.CurveID{tls.CurveP256},
// Use modern tls mode https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility
NextProtos: []string{"http/1.1", "h2"},
NextProtos: []string{"h2", "http/1.1"},
// https://www.owasp.org/index.php/Transport_Layer_Protection_Cheat_Sheet#Rule_-_Only_Support_Strong_Protocols
MinVersion: tls.VersionTLS12,
// These ciphersuites support Forward Secrecy: https://en.wikipedia.org/wiki/Forward_secrecy
@@ -293,7 +290,7 @@ func (s *Server) Serve() (err error) {
// call custom TLS configurator
configureTLS(httpsServer.TLSConfig)
if len(httpsServer.TLSConfig.Certificates) == 0 {
if len(httpsServer.TLSConfig.Certificates) == 0 && httpsServer.TLSConfig.GetCertificate == nil {
// after standard and custom config are passed, this ends up with no certificate
if s.TLSCertificate == "" {
if s.TLSCertificateKey == "" {
@@ -325,6 +322,9 @@ func (s *Server) Serve() (err error) {
}(tls.NewListener(s.httpsServerL, httpsServer.TLSConfig))
}
wg.Add(1)
go s.handleShutdown(wg, &servers)
wg.Wait()
return nil
}
@@ -420,6 +420,9 @@ func (s *Server) handleShutdown(wg *sync.WaitGroup, serversPtr *[]*http.Server)
ctx, cancel := context.WithTimeout(context.TODO(), s.GracefulTimeout)
defer cancel()
// first execute the pre-shutdown hook
s.api.PreServerShutdown()
shutdownChan := make(chan bool)
for i := range servers {
server := servers[i]
@@ -489,7 +492,7 @@ func (s *Server) TLSListener() (net.Listener, error) {
func handleInterrupt(once *sync.Once, s *Server) {
once.Do(func() {
for _ = range s.interrupt {
for range s.interrupt {
if s.interrupted {
s.Logf("Server already shutting down")
continue

View File

@@ -137,17 +137,17 @@ limitations under the License.
<div id="heatmap-body" style="padding: 10px"></div>
<div class="input-group">
<span class="input-group-addon" style="width: 200px">Good treshold</span>
<span class="input-group-addon" style="width: 200px">Good threshold</span>
<input id="t0" type="number" step="1" class="form-control" placeholder="2" value="2">
<span class="input-group-addon">milliseconds</span>
</div>
<div class="input-group">
<span class="input-group-addon" style="width: 200px">Warning treshold</span>
<span class="input-group-addon" style="width: 200px">Warning threshold</span>
<input id="t1" type="number" step="1" class="form-control" placeholder="5" value="5">
<span class="input-group-addon">milliseconds</span>
</div>
<div class="input-group">
<span class="input-group-addon" style="width: 200px">Problem treshold</span>
<span class="input-group-addon" style="width: 200px">Problem threshold</span>
<input id="t2" type="number" step="1" class="form-control" placeholder="100" value="100">
<span class="input-group-addon">milliseconds</span>
</div>
@@ -248,15 +248,19 @@ var main = function(timeout){
var edges = [];
var resp = data.responses;
for (let callId in resp) {
var call = resp[callId].response['podResults'];
if (typeof call !== 'string'){
for (let target in call) {
edges.push({
source: callId,
target: target,
_data: call[target]
});
};
// If there was an error, the response can be undefined,
// especially if there was a timeout/context exceeded
if (resp[callId].response !== undefined) {
var call = resp[callId].response['podResults'];
if (typeof call !== 'string'){
for (let target in call) {
edges.push({
source: callId,
target: target,
_data: call[target]
});
};
}
}
};
@@ -480,6 +484,3 @@ $("#update-heatmap").click(function (e) {
</script>
</body>
</html>

View File

@@ -1,8 +1,8 @@
---
swagger: '2.0'
info:
version: 2.0.0
title: Goldpinger
version: 3.0.0
title: Goldpinger
definitions:
CallStats:
properties:
@@ -37,6 +37,12 @@ definitions:
OK:
type: boolean
default: false
PingTime:
format: date-time
type: string
PodIP:
type: string
format: ipv4
HostIP:
type: string
format: ipv4
@@ -66,6 +72,9 @@ definitions:
OK:
type: boolean
default: false
PodIP:
type: string
format: ipv4
HostIP:
type: string
format: ipv4
@@ -83,16 +92,18 @@ definitions:
type: boolean
default: false
hosts-healthy:
type: integer
type: integer
format: int32
hosts-number:
type: integer
type: integer
format: int32
hosts:
type: array
items:
type: object
properties:
podName:
type: string
hostIP:
type: string
format: ipv4
@@ -124,8 +135,8 @@ paths:
get:
description: return query stats
produces:
- application/json
operationId: ping
- application/json
operationId: ping
responses:
200:
description: return success
@@ -136,11 +147,11 @@ paths:
description: Queries the API server for all other pods in this service,
and pings them via their pods IPs. Calls their /ping endpoint
produces:
- application/json
operationId: checkServicePods
- application/json
operationId: checkServicePods
responses:
200:
description: Success, return response
description: Success, return response
schema:
$ref: '#/definitions/CheckResults'
/check_all:
@@ -149,11 +160,11 @@ paths:
and makes all of them query all of their neighbours,
using their pods IPs. Calls their /check endpoint.
produces:
- application/json
operationId: checkAllPods
- application/json
operationId: checkAllPods
responses:
200:
description: Success, return response
description: Success, return response
schema:
$ref: '#/definitions/CheckAllResults'
/healthz: